Merge "Clear temp list after call"
diff --git a/Android.bp b/Android.bp
index 3b6eaa7..d04eb17 100644
--- a/Android.bp
+++ b/Android.bp
@@ -34,6 +34,27 @@
     path: "core/java",
 }
 
+// These are subset of framework-core-sources that are needed by the
+// android.test.mock library. Ideally, the library should use public APIs only,
+// but unfortunately its API signature has some references to these private APIs.
+filegroup {
+    name: "framework-core-sources-for-test-mock",
+    srcs: [
+        "core/java/android/app/IApplicationThread.aidl",
+        "core/java/android/app/IServiceConnection.aidl",
+        "core/java/android/content/IContentProvider.java",
+        "core/java/android/content/pm/IPackageDataObserver.aidl",
+        "core/java/android/content/pm/InstantAppInfo.java",
+        "core/java/android/content/pm/KeySet.java",
+        "core/java/android/content/pm/PackageManager.java",
+        "core/java/android/content/pm/VerifierDeviceIdentity.java",
+        "core/java/android/content/res/Resources.java",
+        "core/java/android/os/storage/VolumeInfo.java",
+        "core/java/android/view/DisplayAdjustments.java",
+    ],
+    path: "core/java",
+}
+
 filegroup {
     name: "framework-drm-sources",
     srcs: [
@@ -307,6 +328,7 @@
         "android.hardware.thermal-V1.1-java",
         "android.hardware.thermal-V2.0-java",
         "android.hardware.tv.input-V1.0-java-constants",
+        "android.hardware.tv.tuner-V1.0-java-constants",
         "android.hardware.usb-V1.0-java-constants",
         "android.hardware.usb-V1.1-java-constants",
         "android.hardware.usb-V1.2-java-constants",
@@ -402,16 +424,8 @@
     name: "framework-minus-apex",
     defaults: ["framework-defaults"],
     srcs: [":framework-non-updatable-sources"],
-    javac_shard_size: 150,
-}
-
-java_library {
-    name: "framework",
-    defaults: ["framework-aidl-export-defaults"],
     installable: true,
-    static_libs: [
-        "framework-minus-apex",
-    ],
+    javac_shard_size: 150,
     required: [
         "framework-platform-compat-config",
         "libcore-platform-compat-config",
@@ -419,6 +433,27 @@
         "media-provider-platform-compat-config",
         "services-devicepolicy-platform-compat-config",
     ],
+    // For backwards compatibility.
+    stem: "framework",
+}
+
+// This "framework" module is NOT installed to the device. It's
+// "framework-minus-apex" that gets installed to the device. Note that
+// the filename is still framework.jar (via the stem property) for
+// compatibility reason. The purpose of this module is to provide
+// framework APIs (both public and private) for bundled apps.
+// "framework-minus-apex" can't be used for the purpose because 1)
+// many apps have already hardcoded the name "framework" and
+// 2) it lacks API symbols from updatable modules - as it's clear from
+// its suffix "-minus-apex".
+java_library {
+    name: "framework",
+    defaults: ["framework-aidl-export-defaults"],
+    installable: false, // this lib is a build-only library
+    static_libs: [
+        "framework-minus-apex",
+        // TODO(jiyong): add stubs for APEXes here
+    ],
     sdk_version: "core_platform",
 }
 
@@ -548,6 +583,12 @@
     ],
 }
 
+filegroup {
+    name: "framework-tethering-shared-srcs",
+    srcs: [
+        "core/java/android/util/LocalLog.java",
+    ],
+}
 // Build ext.jar
 // ============================================================
 java_library {
@@ -916,13 +957,16 @@
 ]
 
 metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " +
+    "--ignore-classes-on-classpath " +
     "--hide-package com.android.okhttp " +
     "--hide-package com.android.org.conscrypt --hide-package com.android.server " +
     "--error UnhiddenSystemApi " +
     "--hide RequiresPermission " +
+    "--hide CallbackInterface " +
     "--hide MissingPermission --hide BroadcastBehavior " +
     "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " +
-    "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo "
+    "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo " +
+    "--force-convert-to-warning-nullability-annotations +*:-android.*:+android.icu.*:-dalvik.*"
 
 // http://b/129765390 Rewrite links to "platform" or "technotes" folders
 // which are siblings (and thus outside of) {@docRoot}.
@@ -1402,8 +1446,6 @@
     name: "hiddenapi-mappings",
     defaults: ["metalava-api-stubs-default"],
     srcs: [
-        ":non_openjdk_java_files",
-        ":openjdk_java_files",
         ":opt-telephony-common-srcs",
     ],
 
@@ -1419,29 +1461,6 @@
         " --show-annotation android.annotation.TestApi ",
 }
 
-filegroup {
-    name: "apache-http-stubs-sources",
-    srcs: [
-        "core/java/org/apache/http/conn/ConnectTimeoutException.java",
-        "core/java/org/apache/http/conn/scheme/HostNameResolver.java",
-        "core/java/org/apache/http/conn/scheme/LayeredSocketFactory.java",
-        "core/java/org/apache/http/conn/scheme/SocketFactory.java",
-        "core/java/org/apache/http/conn/ssl/AbstractVerifier.java",
-        "core/java/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java",
-        "core/java/org/apache/http/conn/ssl/AndroidDistinguishedNameParser.java",
-        "core/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java",
-        "core/java/org/apache/http/conn/ssl/SSLSocketFactory.java",
-        "core/java/org/apache/http/conn/ssl/StrictHostnameVerifier.java",
-        "core/java/org/apache/http/conn/ssl/X509HostnameVerifier.java",
-        "core/java/org/apache/http/params/CoreConnectionPNames.java",
-        "core/java/org/apache/http/params/HttpConnectionParams.java",
-        "core/java/org/apache/http/params/HttpParams.java",
-        "core/java/android/net/http/SslCertificate.java",
-        "core/java/android/net/http/SslError.java",
-        "core/java/com/android/internal/util/HexDump.java",
-    ],
-}
-
 droidstubs {
     name: "api-stubs-docs",
     defaults: ["metalava-api-stubs-default"],
@@ -1517,6 +1536,10 @@
             api_file: "api/test-current.txt",
             removed_api_file: "api/test-removed.txt",
         },
+        api_lint: {
+            enabled: true,
+            baseline_file: "api/test-lint-baseline.txt",
+        },
     },
 }
 
@@ -1576,13 +1599,16 @@
         "core/java/android/util/Slog.java",
         "core/java/android/util/TimeUtils.java",
         "core/java/com/android/internal/os/SomeArgs.java",
+        "core/java/com/android/internal/util/ArrayUtils.java",
+        "core/java/com/android/internal/util/DumpUtils.java",
+        "core/java/com/android/internal/util/FastXmlSerializer.java",
+        "core/java/com/android/internal/util/HexDump.java",
+        "core/java/com/android/internal/util/IndentingPrintWriter.java",
         "core/java/com/android/internal/util/Preconditions.java",
         "core/java/com/android/internal/util/State.java",
         "core/java/com/android/internal/util/StateMachine.java",
+        "core/java/com/android/internal/util/UserIcons.java",
         "core/java/com/android/internal/util/XmlUtils.java",
-        "core/java/com/android/internal/util/HexDump.java",
-        "core/java/com/android/internal/util/IndentingPrintWriter.java",
-        "core/java/com/android/internal/util/DumpUtils.java"
     ],
 }
 
@@ -1599,9 +1625,20 @@
 }
 
 filegroup {
+    name: "framework-ims-common-shared-srcs",
+    srcs: [
+        "core/java/android/os/RegistrantList.java",
+        "core/java/android/os/Registrant.java",
+        "core/java/com/android/internal/os/SomeArgs.java",
+        "core/java/com/android/internal/util/Preconditions.java",
+    ],
+}
+
+filegroup {
     name: "framework-wifistack-shared-srcs",
     srcs: [
         ":framework-annotations",
+	"core/java/android/os/HandlerExecutor.java",
         "core/java/android/util/KeyValueListParser.java",
         "core/java/android/util/LocalLog.java",
         "core/java/android/util/Rational.java",
diff --git a/apex/jobscheduler/framework/java/android/app/DeviceIdleFrameworkInitializer.java b/apex/jobscheduler/framework/java/android/app/DeviceIdleFrameworkInitializer.java
index 5b14056..c264531 100644
--- a/apex/jobscheduler/framework/java/android/app/DeviceIdleFrameworkInitializer.java
+++ b/apex/jobscheduler/framework/java/android/app/DeviceIdleFrameworkInitializer.java
@@ -19,36 +19,17 @@
 import android.content.Context;
 import android.os.DeviceIdleManager;
 import android.os.IDeviceIdleController;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 
 /**
- * This class needs to be pre-loaded by zygote.  This is where the device idle manager wrapper
- * is registered.
- *
  * @hide
  */
 public class DeviceIdleFrameworkInitializer {
     private static IDeviceIdleController sIDeviceIdleController;
 
-    static {
+    public static void initialize() {
         SystemServiceRegistry.registerCachedService(
                 Context.DEVICE_IDLE_CONTROLLER, DeviceIdleManager.class,
                 (context, b) -> new DeviceIdleManager(
                         context, IDeviceIdleController.Stub.asInterface(b)));
-        PowerManager.setIsIgnoringBatteryOptimizationsCallback((packageName) -> {
-            // No need for synchronization on sIDeviceIdleController; worst case
-            // we just initialize it twice.
-            if (sIDeviceIdleController == null) {
-                sIDeviceIdleController = IDeviceIdleController.Stub.asInterface(
-                        ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
-            }
-            try {
-                return sIDeviceIdleController.isPowerSaveWhitelistApp(packageName);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-        });
     }
 }
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
index 150cdbc..42cf17b 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
@@ -68,7 +68,11 @@
             REASON_DEVICE_THERMAL,
     };
 
-    /** @hide */
+    /**
+     * @hide
+     * @deprecated use {@link #getReasonCodeDescription(int)}
+     */
+    @Deprecated
     public static String getReasonName(int reason) {
         switch (reason) {
             case REASON_CANCELED: return "canceled";
@@ -81,6 +85,20 @@
         }
     }
 
+    /** @hide */
+    // @SystemApi TODO make it a system api for mainline
+    @NonNull
+    public static int[] getJobStopReasonCodes() {
+        return JOB_STOP_REASON_CODES;
+    }
+
+    /** @hide */
+    // @SystemApi TODO make it a system api for mainline
+    @NonNull
+    public static String getReasonCodeDescription(int reasonCode) {
+        return getReasonName(reasonCode);
+    }
+
     @UnsupportedAppUsage
     private final int jobId;
     private final PersistableBundle extras;
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java b/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java
index c90b872..175e5f2 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java
@@ -19,21 +19,14 @@
 import android.app.JobSchedulerImpl;
 import android.app.SystemServiceRegistry;
 import android.content.Context;
-import android.os.BatteryStats;
 
 /**
- * This class needs to be pre-loaded by zygote.  This is where the job scheduler service wrapper
- * is registered.
- *
  * @hide
  */
 public class JobSchedulerFrameworkInitializer {
-    static {
+    public static void initialize() {
         SystemServiceRegistry.registerStaticService(
                 Context.JOB_SCHEDULER_SERVICE, JobScheduler.class,
                 (b) -> new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b)));
-
-        BatteryStats.setJobStopReasons(JobParameters.JOB_STOP_REASON_CODES,
-                JobParameters::getReasonName);
     }
 }
diff --git a/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java b/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java
index e27670c..0568beb 100644
--- a/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java
+++ b/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java
@@ -84,4 +84,17 @@
             return 0;
         }
     }
+
+    /**
+     * Return whether a given package is in the power-save whitelist or not.
+     * @hide
+     */
+    public boolean isApplicationWhitelisted(@NonNull String packageName) {
+        try {
+            return mService.isPowerSaveWhitelistApp(packageName);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+            return false;
+        }
+    }
 }
diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
index c036c77..041825c 100644
--- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
@@ -1,9 +1,9 @@
 package com.android.server.usage;
 
+import android.annotation.UserIdInt;
 import android.app.usage.AppStandbyInfo;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStatsManager.StandbyBuckets;
-import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
 import android.content.Context;
 import android.os.Looper;
 
@@ -33,6 +33,24 @@
         }
     }
 
+    /**
+     * Listener interface for notifications that an app's idle state changed.
+     */
+    abstract static class AppIdleStateChangeListener {
+
+        /** Callback to inform listeners that the idle state has changed to a new bucket. */
+        public abstract void onAppIdleStateChanged(String packageName, @UserIdInt int userId,
+                boolean idle, int bucket, int reason);
+
+        /**
+         * Optional callback to inform the listener that the app has transitioned into
+         * an active state due to user interaction.
+         */
+        public void onUserInteractionStarted(String packageName, @UserIdInt int userId) {
+            // No-op by default
+        }
+    }
+
     void onBootPhase(int phase);
 
     void postCheckIdleStates(int userId);
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 c3ffad6..593e494 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -37,7 +37,6 @@
 import android.app.job.JobWorkItem;
 import android.app.usage.UsageStatsManager;
 import android.app.usage.UsageStatsManagerInternal;
-import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -60,9 +59,7 @@
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.ResultReceiver;
 import android.os.ServiceManager;
-import android.os.ShellCallback;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
@@ -103,6 +100,8 @@
 import com.android.server.job.controllers.TimeController;
 import com.android.server.job.restrictions.JobRestriction;
 import com.android.server.job.restrictions.ThermalStatusRestriction;
+import com.android.server.usage.AppStandbyInternal;
+import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
 
 import libcore.util.EmptyArray;
 
@@ -898,7 +897,8 @@
     }
 
     final private IUidObserver mUidObserver = new IUidObserver.Stub() {
-        @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
+        @Override public void onUidStateChanged(int uid, int procState, long procStateSeq,
+                int capability) {
             mHandler.obtainMessage(MSG_UID_STATE_CHANGED, uid, procState).sendToTarget();
         }
 
@@ -1295,7 +1295,9 @@
         // Set up the app standby bucketing tracker
         mStandbyTracker = new StandbyTracker();
         mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
-        mUsageStats.addAppIdleStateChangeListener(mStandbyTracker);
+
+        AppStandbyInternal appStandby = LocalServices.getService(AppStandbyInternal.class);
+        appStandby.addListener(mStandbyTracker);
 
         // The job store needs to call back
         publishLocalService(JobSchedulerInternal.class, new LocalService());
@@ -2686,12 +2688,13 @@
         }
 
         @Override
-        public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
-                String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
-                (new JobSchedulerShellCommand(JobSchedulerService.this)).exec(
-                        this, in, out, err, args, callback, resultReceiver);
+        protected int handleShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out,
+                @NonNull FileDescriptor err, @NonNull String[] args) {
+            return (new JobSchedulerShellCommand(JobSchedulerService.this)).exec(
+                    this, in, out, err, args);
         }
 
+
         /**
          * <b>For internal system user only!</b>
          * Returns a list of all currently-executing 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 01d158ba..a5c6c01 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -20,13 +20,13 @@
 import android.app.AppGlobals;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
+import android.os.BasicShellCommandHandler;
 import android.os.Binder;
-import android.os.ShellCommand;
 import android.os.UserHandle;
 
 import java.io.PrintWriter;
 
-public final class JobSchedulerShellCommand extends ShellCommand {
+public final class JobSchedulerShellCommand extends BasicShellCommandHandler {
     public static final int CMD_ERR_NO_PACKAGE = -1000;
     public static final int CMD_ERR_NO_JOB = -1001;
     public static final int CMD_ERR_CONSTRAINTS = -1002;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 14dce84..3aef5d1 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -35,8 +35,6 @@
 import android.app.AlarmManager;
 import android.app.AppGlobals;
 import android.app.IUidObserver;
-import android.app.usage.UsageStatsManagerInternal;
-import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -70,6 +68,8 @@
 import com.android.server.job.JobSchedulerService;
 import com.android.server.job.JobServiceContext;
 import com.android.server.job.StateControllerProto;
+import com.android.server.usage.AppStandbyInternal;
+import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -466,7 +466,7 @@
 
     private final IUidObserver mUidObserver = new IUidObserver.Stub() {
         @Override
-        public void onUidStateChanged(int uid, int procState, long procStateSeq) {
+        public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) {
             mHandler.obtainMessage(MSG_UID_PROCESS_STATE_CHANGED, uid, procState).sendToTarget();
         }
 
@@ -574,9 +574,8 @@
         mContext.registerReceiverAsUser(mPackageAddedReceiver, UserHandle.ALL, filter, null, null);
 
         // Set up the app standby bucketing tracker
-        UsageStatsManagerInternal usageStats = LocalServices.getService(
-                UsageStatsManagerInternal.class);
-        usageStats.addAppIdleStateChangeListener(new StandbyTracker());
+        AppStandbyInternal appStandby = LocalServices.getService(AppStandbyInternal.class);
+        appStandby.addListener(new StandbyTracker());
 
         try {
             ActivityManager.getService().registerUidObserver(mUidObserver,
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 ecc0459..bcd8be7 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -53,7 +53,6 @@
 import android.app.usage.AppStandbyInfo;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStatsManager.StandbyBuckets;
-import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
 import android.appwidget.AppWidgetManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -102,6 +101,7 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.LocalServices;
 import com.android.server.usage.AppIdleHistory.AppUsageHistory;
+import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
 
 import java.io.File;
 import java.io.PrintWriter;
diff --git a/apex/permission/Android.bp b/apex/permission/Android.bp
new file mode 100644
index 0000000..0274814
--- /dev/null
+++ b/apex/permission/Android.bp
@@ -0,0 +1,33 @@
+// 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.
+
+apex {
+    name: "com.android.permission",
+
+    manifest: "apex_manifest.json",
+
+    key: "com.android.permission.key",
+    certificate: ":com.android.permission.certificate",
+}
+
+apex_key {
+    name: "com.android.permission.key",
+    public_key: "com.android.permission.avbpubkey",
+    private_key: "com.android.permission.pem",
+}
+
+android_app_certificate {
+    name: "com.android.permission.certificate",
+    certificate: "com.android.permission",
+}
diff --git a/apex/permission/OWNERS b/apex/permission/OWNERS
new file mode 100644
index 0000000..957e10a
--- /dev/null
+++ b/apex/permission/OWNERS
@@ -0,0 +1,6 @@
+svetoslavganov@google.com
+moltmann@google.com
+eugenesusla@google.com
+zhanghai@google.com
+evanseverson@google.com
+ntmyren@google.com
diff --git a/apex/permission/apex_manifest.json b/apex/permission/apex_manifest.json
new file mode 100644
index 0000000..2a8c4f7
--- /dev/null
+++ b/apex/permission/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.permission",
+  "version": 1
+}
diff --git a/apex/permission/com.android.permission.avbpubkey b/apex/permission/com.android.permission.avbpubkey
new file mode 100644
index 0000000..9eaf852
--- /dev/null
+++ b/apex/permission/com.android.permission.avbpubkey
Binary files differ
diff --git a/apex/permission/com.android.permission.pem b/apex/permission/com.android.permission.pem
new file mode 100644
index 0000000..3d584be
--- /dev/null
+++ b/apex/permission/com.android.permission.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKgIBAAKCAgEA6snt4eqoz85xiL9Sf6w1S1b9FgSHK05zYTh2JYPvQKQ3yeZp
+E6avJ6FN6XcbmkDzSd658BvUGDBSPhOlzuUO4BsoKBuLMxP6TxIQXFKidzDqY0vQ
+4qkS++bdIhUjwBP3OSZ3Czu0BiihK8GC75Abr//EyCyObGIGGfHEGANiOgrpP4X5
++OmLzQLCjk4iE1kg+U6cRSRI/XLaoWC0TvIIuzxznrQ6r5GmzgTOwyBWyIB+bj73
+bmsweHTU+w9Y7kGOx4hO3XCLIhoBWEw0EbuW9nZmQ4sZls5Jo/CbyJlCclF11yVo
+SCf2LG/T+9pah5NOmDQ1kPbU+0iKZIV4YFHGTIhyGDE/aPOuUT05ziCGDifgHr0u
+SG1x/RLqsVh/POvNxnvP9cQFMQ08BvbEJaTTgB785iwKsvdqCfmng/SAyxSetmzP
+StXVB3fh1OoZ8vunRbQYxnmUxycVqaA96zmBx2wLvbvzKo7pZFDE6nbhnT5+MRAM
+z/VIK89W26uB4gj8sBFslqZjT0jPqsAZuvDm7swOtMwIcEolyGJuFLqlhN7UwMz2
+9y8+IpYixR+HvD1TZI9NtmuCmv3kPrWgoMZg6yvaBayTIr8RdYzi6FO/C1lLiraz
+48dH3sXWRa8cgw6VcSUwYrEBIc3sotdsupO1iOjcFybIwaee0YTZJfjvbqkCAwEA
+AQKCAgEArRnfdpaJi1xLPGTCMDsIt9kUku0XswgN7PmxsYsKFAB+2S40/jYAIRm9
+1YjpItsMA8RgFfSOdJ77o6TctCMQyo17F8bm4+uwuic5RLfv7Cx2QmsdQF8jDfFx
+y7UGPJD7znjbf76uxXOjEB2FqZX3s9TAgkzHXIUQtoQW7RVhkCWHPjxKxgd5+NY2
+FrDoUpd9xhD9CcTsw1+wbRZdGW88nL6/B50dP2AFORM2VYo8MWr6y9FEn3YLsGOC
+uu7fxBk1aUrHyl81VRkTMMROB1zkuiUk1FtzrEm+5U15rXXBFYOVe9+qeLhtuOlh
+wueDoz0pzvF/JLe24uTik6YL0Ae6SD0pFXQ2KDrdH3cUHLok3r76/yGzaDNTFjS2
+2WbQ8dEJV8veNHk8gjGpFTJIsBUlcZpmUCDHlfvVMb3+2ahQ+28piQUt5t3zqJdZ
+NDqsOHzY6BRPc+Wm85Xii/lWiQceZSee/b1Enu+nchsyXhSenBfC6bIGZReyMI0K
+KKKuVhyR6OSOiR5ZdZ/NyXGqsWy05fn/h0X9hnpETsNaNYNKWvpHLfKll+STJpf7
+AZquJPIclQyiq5NONx6kfPztoCLkKV/zOgIj3Sx5oSZq+5gpO91nXWVwkTbqK1d1
+004q2Mah6UQyAk1XGQc2pHx7ouVcWawjU30vZ4C015Hv2lm/gVkCggEBAPltATYS
+OqOSL1YAtIHPiHxMjNAgUdglq8JiJFXVfkocGU9eNub3Ed3sSWu6GB9Myu/sSKje
+bJ5DZqxJnvB2Fqmu9I9OunLGFSD0aXs4prwsQ1Rm5FcbImtrxcciASdkoo8Pj0z4
+vk2r2NZD3VtER5Uh+YjSDkxcS9gBStXUpCL6gj69UpOxMmWqZVjyHatVB4lEvYJl
+N82uT7N7QVNL1DzcZ9z4C4r7ks1Pm7ka12s5m/oaAlAMdVeofiPJe1xA9zRToSr4
+tIbMkOeXFLVRLuji/7XsOgal5Rl59p+OwLshX5cswPVOMrH6zt+hbsJ5q8M5dqnX
+VAOBK7KNQ/EKZwcCggEBAPD6KVvyCim46n5EbcEqCkO7gevwZkw/9vLwmM5YsxTh
+z9FQkPO0iB7mwbX8w04I91Pre4NdfcgMG0pP1b13Sb4KHBchqW1a+TCs3kSGC6gn
+1SxmXHnA9jRxAkrWlGkoAQEz+aP61cXiiy2tXpQwJ8xQCKprfoqWZwhkCtEVU6CE
+S7v9cscOHIqgNxx4WoceMmq4EoihHAZzHxTcNVbByckMjb2XQJ0iNw3lDP4ddvc+
+a4HzHfHkhzeQ5ZNc8SvWU8z80aSCOKRsSD3aUTZzxhZ4O2tZSW7v7p+FpvVee7bC
+g8YCfszTdpVUMlLRLjScimAcovcFLSvtyupinxWg4M8CggEAN9YGEmOsSte7zwXj
+YrfhtumwEBtcFwX/2Ej+F1Tuq4p0xAa0RaoDjumJWhtTsRYQy/raHSuFpzwxbNoi
+QXQ+CIhI6RfXtz/OlQ0B2/rHoJJMFEXgUfuaDfAXW0eqeHYXyezSyIlamKqipPyW
+Pgsf9yue39keKEv1EorfhNTQVaA8rezV4oglXwrxGyNALw2e3UTNI7ai8mFWKDis
+XAg6n9E7UwUYGGnO6DUtCBgRJ0jDOQ6/e8n+LrxiWIKPIgzNCiK6jpMUXqTGv4Fb
+umdNGAdQ9RnHt5tFmRlrczaSwJFtA7uaCpAR2zPpQbiywchZAiAIB2dTwGEXNiZX
+kksg2wKCAQEA6pNad3qhkgPDoK6T+Jkn7M82paoaqtcJWWwEE7oceZNnbWZz9Agl
+CY+vuawXonrv5+0vCq2Tp4zBdBFLC2h3jFrjBVFrUFxifpOIukOSTVqZFON/2bWQ
+9XOcu6UuSz7522Xw+UNPnZXtzcUacD6AP08ZYGvLfrTyDyTzspyED5k48ALEHCkM
+d5WGkFxII4etpF0TDZVnZo/iDbhe49k4yFFEGO6Ho26PESOLBkNAb2V/2bwDxlij
+l9+g21Z6HiZA5SamHPH2mXgeyrcen1cL2QupK9J6vVcqfnboE6qp2zp2c+Yx8MlY
+gfy4EA44YFaSDQVTTgrn8f9Eq+zc130H2QKCAQEAqOKgv68nIPdDSngNyCVyWego
+boFiDaEJoBBg8FrBjTJ6wFLrNAnXmbvfTtgNmNAzF1cUPJZlIIsHgGrMCfpehbXq
+WQQIw+E+yFbTGLxseGRfsLrV0CsgnAoOVeod+yIHmqc3livaUbrWhL1V2f6Ue+sE
+7YLp/iP43NaMfA4kYk2ep7+ZJoEVkCjHJJaHWgAG3RynPJHkTJlSgu7wLYvGc9uE
+ZsEFUM46lX02t7rrtMfasVGrUy1c2xOxFb4v1vG6iEZ7+YWeq5o3AkxUwEGn+mG4
+/3p+k4AaTXJDXgyZ0Sv6CkGuPHenAYG4cswcUUEf/G4Ag77x6LBNMgycJBxUJA==
+-----END RSA PRIVATE KEY-----
diff --git a/apex/permission/com.android.permission.pk8 b/apex/permission/com.android.permission.pk8
new file mode 100644
index 0000000..d51673d
--- /dev/null
+++ b/apex/permission/com.android.permission.pk8
Binary files differ
diff --git a/apex/permission/com.android.permission.x509.pem b/apex/permission/com.android.permission.x509.pem
new file mode 100644
index 0000000..4b146c9
--- /dev/null
+++ b/apex/permission/com.android.permission.x509.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGKzCCBBOgAwIBAgIUezo3fQeVZsmLpm/dkpGWJ/G/MN8wDQYJKoZIhvcNAQEL
+BQAwgaMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
+b2lkMR8wHQYDVQQDDBZjb20uYW5kcm9pZC5wZXJtaXNzaW9uMSIwIAYJKoZIhvcN
+AQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tMCAXDTE5MTAwOTIxMzExOVoYDzQ3NTcw
+OTA0MjEzMTE5WjCBozELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWEx
+FjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB0FuZHJvaWQxEDAOBgNV
+BAsMB0FuZHJvaWQxHzAdBgNVBAMMFmNvbS5hbmRyb2lkLnBlcm1pc3Npb24xIjAg
+BgkqhkiG9w0BCQEWE2FuZHJvaWRAYW5kcm9pZC5jb20wggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQCxefguRJ7E6tBCTEOeU2HJEGs6AQQapLz9hMed0aaJ
+Qr7aTQiYJEk+sG4+jPYbjpxa8JDDzJHp+4g7DjfSb+dvT9n84A8lWaI/yRXTZTQN
+Hu5m/bgHhi0LbySpiaFyodXBKUAnOhZyGPtYjtBFywFylueub8ryc1Z6UxxU7udH
+1mkIr7sE48Qkq5SyjFROE96iFmYA+vS/JXOfS0NBHiMB4GBxx4V7kXpvrTI7hhZG
+HiyhKvNh7wyHIhO9nDEw1rwtAH6CsL3YkQEVBeAU98m+0Au+qStLYkKHh2l8zT4W
+7sVK1VSqfB+VqOUmeIGdzlBfqMsoXD+FJz6KnIdUHIwjFDjL7Xr+hd+7xve+Q3S+
+U3Blk/U6atY8PM09wNfilG+SvwcKk5IgriDcu3rWKgIFxbUUaxLrDW7pLlu6wt/d
+GGtKK+Bc0jF+9Z901Tl33i5xhc5yOktT0btkKs7lSeE6VzP/Nk5g0SuzixmuRoh9
+f5Ge41N2ZCEHNXx3wZeVZwHIIPfYrL7Yql1Xoxbfs4ETFk6ChzVQcvjfDQQuK58J
+uNc+TOCoI/qflXwGCwpuHl0ier8V5Z4tpMUl5rWyVR/QGRtLPvs2lLuxczDw1OXq
+wEVtCMn9aNnd4y7R9PZ52hi53HAvDjpWefrLYi+Q04J6iGFQ1qAFBClK9DquBvmR
+swIDAQABo1MwUTAdBgNVHQ4EFgQULpfus5s5SrqLkoUKyPXA0D1iHPMwHwYDVR0j
+BBgwFoAULpfus5s5SrqLkoUKyPXA0D1iHPMwDwYDVR0TAQH/BAUwAwEB/zANBgkq
+hkiG9w0BAQsFAAOCAgEAjxQG5EFv8V/9yV2glI53VOmlWMjfEgvUjd39s/XLyPlr
+OzPOKSB0NFo8To3l4l+MsManxPK8y0OyfEVKbWVz9onv0ovo5MVokBmV/2G0jmsV
+B4e9yjOq+DmqIvY/Qh63Ywb97sTgcFI8620MhQDbh2IpEGv4ZNV0H6rgXmgdSCBw
+1EjBoYfFpN5aMgZjeyzZcq+d1IapdWqdhuEJQkMvoYS4WIumNIJlEXPQRoq/F5Ih
+nszdbKI/jVyiGFa2oeZ3rja1Y6GCRU8TYEoKx1pjS8uQDOEDTwsG/QnUe9peEj0V
+SsCkIidJWTomAmq9Tub9vpBe1zuTpuRAwxwR0qwgSxozV1Mvow1dJ19oFtHX0yD6
+ZjCpRn5PW9kMvSWSlrcrFs1NJf0j1Cvf7bHpkEDqLqpMnnh9jaFQq3nzDY+MWcIR
+jDcgQpI+AiE2/qtauZnFEVhbce49nCnk9+5bpTTIZJdzqeaExe5KXHwEtZLaEDh4
+atLY9LuEvPsjmDIMOR6hycD9FvwGXhJOQBjESIWFwigtSb1Yud9n6201jw3MLJ4k
++WhkbmZgWy+xc+Mdm5H3XyB1lvHaHGkxu+QB9KyQuVQKwbUVcbwZIfTFPN6Zr/dS
+ZXJqAbBhG/dBgF0LazuLaPVpibi+a3Y+tb9b8eXGkz4F97PWZIEDkELQ+9KOvhc=
+-----END CERTIFICATE-----
diff --git a/apex/statsd/.clang-format b/apex/statsd/.clang-format
new file mode 100644
index 0000000..cead3a0
--- /dev/null
+++ b/apex/statsd/.clang-format
@@ -0,0 +1,17 @@
+BasedOnStyle: Google
+AllowShortIfStatementsOnASingleLine: true
+AllowShortFunctionsOnASingleLine: false
+AllowShortLoopsOnASingleLine: true
+BinPackArguments: true
+BinPackParameters: true
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+ContinuationIndentWidth: 8
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+AccessModifierOffset: -4
+IncludeCategories:
+  - Regex:    '^"Log\.h"'
+    Priority:    -1
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 1a10753..518a29c 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -156,8 +156,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
-import java.time.Instant;
-import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -585,7 +583,11 @@
                         } catch (IllegalArgumentException e) {
                             installer = "";
                         }
-                        sStatsd.informOnePackage(app, uid, pi.getLongVersionCode(), pi.versionName,
+                        sStatsd.informOnePackage(
+                                app,
+                                uid,
+                                pi.getLongVersionCode(),
+                                pi.versionName == null ? "" : pi.versionName,
                                 installer == null ? "" : installer);
                     }
                 } catch (Exception e) {
@@ -2071,9 +2073,7 @@
 
             CompletableFuture<HistoricalOps> ops = new CompletableFuture<>();
             HistoricalOpsRequest histOpsRequest =
-                    new HistoricalOpsRequest.Builder(
-                            Instant.now().minus(1, ChronoUnit.HOURS).toEpochMilli(),
-                            Long.MAX_VALUE).build();
+                    new HistoricalOpsRequest.Builder(0, Long.MAX_VALUE).build();
             appOps.getHistoricalOps(histOpsRequest, mContext.getMainExecutor(), ops::complete);
 
             HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
diff --git a/api/current.txt b/api/current.txt
index 54d33a2..55983c8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2827,7 +2827,7 @@
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
     method @NonNull public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController();
     method @NonNull public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController(int);
-    method @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) @NonNull public final android.accessibilityservice.FingerprintGestureController getFingerprintGestureController();
+    method @NonNull @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public final android.accessibilityservice.FingerprintGestureController getFingerprintGestureController();
     method @NonNull public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
     method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
@@ -3541,11 +3541,11 @@
 
 package android.annotation {
 
-  @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.LOCAL_VARIABLE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface SuppressLint {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.LOCAL_VARIABLE}) public @interface SuppressLint {
     method public abstract String[] value();
   }
 
-  @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface TargetApi {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD}) public @interface TargetApi {
     method public abstract int value();
   }
 
@@ -3758,7 +3758,7 @@
     method public void onContentChanged();
     method public boolean onContextItemSelected(@NonNull android.view.MenuItem);
     method public void onContextMenuClosed(@NonNull android.view.Menu);
-    method @MainThread @CallSuper protected void onCreate(@Nullable android.os.Bundle);
+    method @CallSuper @MainThread protected void onCreate(@Nullable android.os.Bundle);
     method public void onCreate(@Nullable android.os.Bundle, @Nullable android.os.PersistableBundle);
     method public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo);
     method @Nullable public CharSequence onCreateDescription();
@@ -3901,8 +3901,8 @@
     method @Deprecated public void startActivityFromChild(@NonNull android.app.Activity, @RequiresPermission android.content.Intent, int, @Nullable android.os.Bundle);
     method @Deprecated public void startActivityFromFragment(@NonNull android.app.Fragment, @RequiresPermission android.content.Intent, int);
     method @Deprecated public void startActivityFromFragment(@NonNull android.app.Fragment, @RequiresPermission android.content.Intent, int, @Nullable android.os.Bundle);
-    method public boolean startActivityIfNeeded(@RequiresPermission @NonNull android.content.Intent, int);
-    method public boolean startActivityIfNeeded(@RequiresPermission @NonNull android.content.Intent, int, @Nullable android.os.Bundle);
+    method public boolean startActivityIfNeeded(@NonNull @RequiresPermission android.content.Intent, int);
+    method public boolean startActivityIfNeeded(@NonNull @RequiresPermission android.content.Intent, int, @Nullable android.os.Bundle);
     method public void startIntentSenderForResult(android.content.IntentSender, int, @Nullable android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
     method public void startIntentSenderForResult(android.content.IntentSender, int, @Nullable android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method @Deprecated public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
@@ -3910,8 +3910,8 @@
     method public void startLocalVoiceInteraction(android.os.Bundle);
     method public void startLockTask();
     method @Deprecated public void startManagingCursor(android.database.Cursor);
-    method public boolean startNextMatchingActivity(@RequiresPermission @NonNull android.content.Intent);
-    method public boolean startNextMatchingActivity(@RequiresPermission @NonNull android.content.Intent, @Nullable android.os.Bundle);
+    method public boolean startNextMatchingActivity(@NonNull @RequiresPermission android.content.Intent);
+    method public boolean startNextMatchingActivity(@NonNull @RequiresPermission android.content.Intent, @Nullable android.os.Bundle);
     method public void startPostponedEnterTransition();
     method public void startSearch(@Nullable String, boolean, @Nullable android.os.Bundle, boolean);
     method public void stopLocalVoiceInteraction();
@@ -6714,7 +6714,7 @@
     method @NonNull public java.util.Set<java.lang.String> getAffiliationIds(@NonNull android.content.ComponentName);
     method @Nullable public java.util.Set<java.lang.String> getAlwaysOnVpnLockdownWhitelist(@NonNull android.content.ComponentName);
     method @Nullable public String getAlwaysOnVpnPackage(@NonNull android.content.ComponentName);
-    method @WorkerThread @NonNull public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String);
+    method @NonNull @WorkerThread public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String);
     method @Deprecated @Nullable public String getApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName);
     method public boolean getAutoTimeRequired();
     method @NonNull public java.util.List<android.os.UserHandle> getBindDeviceAdminTargetUsers(@NonNull android.content.ComponentName);
@@ -7640,7 +7640,7 @@
     method public int checkSlicePermission(@NonNull android.net.Uri, int, int);
     method @NonNull public java.util.List<android.net.Uri> getPinnedSlices();
     method @NonNull public java.util.Set<android.app.slice.SliceSpec> getPinnedSpecs(android.net.Uri);
-    method @WorkerThread @NonNull public java.util.Collection<android.net.Uri> getSliceDescendants(@NonNull android.net.Uri);
+    method @NonNull @WorkerThread public java.util.Collection<android.net.Uri> getSliceDescendants(@NonNull android.net.Uri);
     method public void grantSlicePermission(@NonNull String, @NonNull android.net.Uri);
     method @Nullable public android.net.Uri mapIntentToUri(@NonNull android.content.Intent);
     method public void pinSlice(@NonNull android.net.Uri, @NonNull java.util.Set<android.app.slice.SliceSpec>);
@@ -7796,10 +7796,10 @@
   public class StorageStatsManager {
     method @WorkerThread public long getFreeBytes(@NonNull java.util.UUID) throws java.io.IOException;
     method @WorkerThread public long getTotalBytes(@NonNull java.util.UUID) throws java.io.IOException;
-    method @WorkerThread @NonNull public android.app.usage.ExternalStorageStats queryExternalStatsForUser(@NonNull java.util.UUID, @NonNull android.os.UserHandle) throws java.io.IOException;
-    method @WorkerThread @NonNull public android.app.usage.StorageStats queryStatsForPackage(@NonNull java.util.UUID, @NonNull String, @NonNull android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException;
-    method @WorkerThread @NonNull public android.app.usage.StorageStats queryStatsForUid(@NonNull java.util.UUID, int) throws java.io.IOException;
-    method @WorkerThread @NonNull public android.app.usage.StorageStats queryStatsForUser(@NonNull java.util.UUID, @NonNull android.os.UserHandle) throws java.io.IOException;
+    method @NonNull @WorkerThread public android.app.usage.ExternalStorageStats queryExternalStatsForUser(@NonNull java.util.UUID, @NonNull android.os.UserHandle) throws java.io.IOException;
+    method @NonNull @WorkerThread public android.app.usage.StorageStats queryStatsForPackage(@NonNull java.util.UUID, @NonNull String, @NonNull android.os.UserHandle) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull @WorkerThread public android.app.usage.StorageStats queryStatsForUid(@NonNull java.util.UUID, int) throws java.io.IOException;
+    method @NonNull @WorkerThread public android.app.usage.StorageStats queryStatsForUser(@NonNull java.util.UUID, @NonNull android.os.UserHandle) throws java.io.IOException;
   }
 
   public final class UsageEvents implements android.os.Parcelable {
@@ -8059,9 +8059,9 @@
     method public boolean isMultipleAdvertisementSupported();
     method public boolean isOffloadedFilteringSupported();
     method public boolean isOffloadedScanBatchingSupported();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) @NonNull public android.bluetooth.BluetoothServerSocket listenUsingInsecureL2capChannel() throws java.io.IOException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingInsecureL2capChannel() throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) @NonNull public android.bluetooth.BluetoothServerSocket listenUsingL2capChannel() throws java.io.IOException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingL2capChannel() throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setName(String);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean startDiscovery();
@@ -8429,9 +8429,9 @@
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int);
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int, android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean createBond();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) @NonNull public android.bluetooth.BluetoothSocket createInsecureL2capChannel(int) throws java.io.IOException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createInsecureL2capChannel(int) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) @NonNull public android.bluetooth.BluetoothSocket createL2capChannel(int) throws java.io.IOException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createL2capChannel(int) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
     method public int describeContents();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean fetchUuidsWithSdp();
@@ -9231,14 +9231,16 @@
 
   public final class WifiDeviceFilter implements android.companion.DeviceFilter<android.net.wifi.ScanResult> {
     method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.companion.WifiDeviceFilter> CREATOR;
   }
 
   public static final class WifiDeviceFilter.Builder {
     ctor public WifiDeviceFilter.Builder();
     method @NonNull public android.companion.WifiDeviceFilter build();
-    method public android.companion.WifiDeviceFilter.Builder setNamePattern(@Nullable java.util.regex.Pattern);
+    method @NonNull public android.companion.WifiDeviceFilter.Builder setBssid(@Nullable android.net.MacAddress);
+    method @NonNull public android.companion.WifiDeviceFilter.Builder setBssidMask(@NonNull android.net.MacAddress);
+    method @NonNull public android.companion.WifiDeviceFilter.Builder setNamePattern(@Nullable java.util.regex.Pattern);
   }
 
 }
@@ -9465,6 +9467,7 @@
     method @NonNull public final android.content.ContentProvider.CallingIdentity clearCallingIdentity();
     method public abstract int delete(@NonNull android.net.Uri, @Nullable String, @Nullable String[]);
     method public void dump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
+    method @Nullable public final String getCallingFeatureId();
     method @Nullable public final String getCallingPackage();
     method @Nullable public final android.content.Context getContext();
     method @Nullable public final android.content.pm.PathPermission[] getPathPermissions();
@@ -9490,6 +9493,7 @@
     method @Nullable public android.database.Cursor query(@NonNull android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String, @Nullable android.os.CancellationSignal);
     method @Nullable public android.database.Cursor query(@NonNull android.net.Uri, @Nullable String[], @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal);
     method public boolean refresh(android.net.Uri, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal);
+    method @NonNull public final android.content.Context requireContext();
     method public final void restoreCallingIdentity(@NonNull android.content.ContentProvider.CallingIdentity);
     method protected final void setPathPermissions(@Nullable android.content.pm.PathPermission[]);
     method protected final void setReadPermission(@Nullable String);
@@ -9612,14 +9616,14 @@
     method public static void addPeriodicSync(android.accounts.Account, String, android.os.Bundle, long);
     method public static Object addStatusChangeListener(int, android.content.SyncStatusObserver);
     method @NonNull public android.content.ContentProviderResult[] applyBatch(@NonNull String, @NonNull java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
-    method public final int bulkInsert(@RequiresPermission.Write @NonNull android.net.Uri, @NonNull android.content.ContentValues[]);
+    method public final int bulkInsert(@NonNull @RequiresPermission.Write android.net.Uri, @NonNull android.content.ContentValues[]);
     method @Nullable public final android.os.Bundle call(@NonNull android.net.Uri, @NonNull String, @Nullable String, @Nullable android.os.Bundle);
     method @Nullable public final android.os.Bundle call(@NonNull String, @NonNull String, @Nullable String, @Nullable android.os.Bundle);
     method @Deprecated public void cancelSync(android.net.Uri);
     method public static void cancelSync(android.accounts.Account, String);
     method public static void cancelSync(android.content.SyncRequest);
     method @Nullable public final android.net.Uri canonicalize(@NonNull android.net.Uri);
-    method public final int delete(@RequiresPermission.Write @NonNull android.net.Uri, @Nullable String, @Nullable String[]);
+    method public final int delete(@NonNull @RequiresPermission.Write android.net.Uri, @Nullable String, @Nullable String[]);
     method @Deprecated public static android.content.SyncInfo getCurrentSync();
     method public static java.util.List<android.content.SyncInfo> getCurrentSyncs();
     method public static int getIsSyncable(android.accounts.Account, String);
@@ -9632,7 +9636,7 @@
     method public static boolean getSyncAutomatically(android.accounts.Account, String);
     method @Nullable public final String getType(@NonNull android.net.Uri);
     method @NonNull public final android.content.ContentResolver.MimeTypeInfo getTypeInfo(@NonNull String);
-    method @Nullable public final android.net.Uri insert(@RequiresPermission.Write @NonNull android.net.Uri, @Nullable android.content.ContentValues);
+    method @Nullable public final android.net.Uri insert(@NonNull @RequiresPermission.Write android.net.Uri, @Nullable android.content.ContentValues);
     method public static boolean isSyncActive(android.accounts.Account, String);
     method public static boolean isSyncPending(android.accounts.Account, String);
     method @NonNull public android.graphics.Bitmap loadThumbnail(@NonNull android.net.Uri, @NonNull android.util.Size, @Nullable android.os.CancellationSignal) throws java.io.IOException;
@@ -9651,9 +9655,9 @@
     method @Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method @Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle) throws java.io.FileNotFoundException;
     method @Nullable public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
-    method @Nullable public final android.database.Cursor query(@RequiresPermission.Read @NonNull android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String);
-    method @Nullable public final android.database.Cursor query(@RequiresPermission.Read @NonNull android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String, @Nullable android.os.CancellationSignal);
-    method @Nullable public final android.database.Cursor query(@RequiresPermission.Read @NonNull android.net.Uri, @Nullable String[], @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal);
+    method @Nullable public final android.database.Cursor query(@NonNull @RequiresPermission.Read android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String);
+    method @Nullable public final android.database.Cursor query(@NonNull @RequiresPermission.Read android.net.Uri, @Nullable String[], @Nullable String, @Nullable String[], @Nullable String, @Nullable android.os.CancellationSignal);
+    method @Nullable public final android.database.Cursor query(@NonNull @RequiresPermission.Read android.net.Uri, @Nullable String[], @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal);
     method public final boolean refresh(@NonNull android.net.Uri, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal);
     method public final void registerContentObserver(@NonNull android.net.Uri, boolean, @NonNull android.database.ContentObserver);
     method public void releasePersistableUriPermission(@NonNull android.net.Uri, int);
@@ -9668,7 +9672,7 @@
     method public void takePersistableUriPermission(@NonNull android.net.Uri, int);
     method @Nullable public final android.net.Uri uncanonicalize(@NonNull android.net.Uri);
     method public final void unregisterContentObserver(@NonNull android.database.ContentObserver);
-    method public final int update(@RequiresPermission.Write @NonNull android.net.Uri, @Nullable android.content.ContentValues, @Nullable String, @Nullable String[]);
+    method public final int update(@NonNull @RequiresPermission.Write android.net.Uri, @Nullable android.content.ContentValues, @Nullable String, @Nullable String[]);
     method public static void validateSyncExtrasBundle(android.os.Bundle);
     method @NonNull public static android.content.ContentResolver wrap(@NonNull android.content.ContentProvider);
     method @NonNull public static android.content.ContentResolver wrap(@NonNull android.content.ContentProviderClient);
@@ -9766,9 +9770,9 @@
 
   public abstract class Context {
     ctor public Context();
-    method public boolean bindIsolatedService(@RequiresPermission @NonNull android.content.Intent, int, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.content.ServiceConnection);
+    method public boolean bindIsolatedService(@NonNull @RequiresPermission android.content.Intent, int, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.content.ServiceConnection);
     method public abstract boolean bindService(@RequiresPermission android.content.Intent, @NonNull android.content.ServiceConnection, int);
-    method public boolean bindService(@RequiresPermission @NonNull android.content.Intent, int, @NonNull java.util.concurrent.Executor, @NonNull android.content.ServiceConnection);
+    method public boolean bindService(@NonNull @RequiresPermission android.content.Intent, int, @NonNull java.util.concurrent.Executor, @NonNull android.content.ServiceConnection);
     method @CheckResult(suggest="#enforceCallingOrSelfPermission(String,String)") public abstract int checkCallingOrSelfPermission(@NonNull String);
     method @CheckResult(suggest="#enforceCallingOrSelfUriPermission(Uri,int,String)") public abstract int checkCallingOrSelfUriPermission(android.net.Uri, int);
     method @CheckResult(suggest="#enforceCallingPermission(String,String)") public abstract int checkCallingPermission(@NonNull String);
@@ -9867,7 +9871,8 @@
     method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
     method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String);
     method public abstract void sendOrderedBroadcast(@RequiresPermission android.content.Intent, @Nullable String);
-    method public abstract void sendOrderedBroadcast(@RequiresPermission @NonNull android.content.Intent, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
+    method public abstract void sendOrderedBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
+    method public void sendOrderedBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
     method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
     method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void sendStickyBroadcast(@RequiresPermission android.content.Intent);
     method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void sendStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
@@ -11721,7 +11726,7 @@
     method @NonNull public abstract android.graphics.drawable.Drawable getUserBadgedDrawableForDensity(@NonNull android.graphics.drawable.Drawable, @NonNull android.os.UserHandle, @Nullable android.graphics.Rect, int);
     method @NonNull public abstract android.graphics.drawable.Drawable getUserBadgedIcon(@NonNull android.graphics.drawable.Drawable, @NonNull android.os.UserHandle);
     method @NonNull public abstract CharSequence getUserBadgedLabel(@NonNull CharSequence, @NonNull android.os.UserHandle);
-    method @RequiresPermission(value="android.permission.WHITELIST_RESTRICTED_PERMISSIONS", conditional=true) @NonNull public java.util.Set<java.lang.String> getWhitelistedRestrictedPermissions(@NonNull String, int);
+    method @NonNull @RequiresPermission(value="android.permission.WHITELIST_RESTRICTED_PERMISSIONS", conditional=true) public java.util.Set<java.lang.String> getWhitelistedRestrictedPermissions(@NonNull String, int);
     method @Nullable public abstract android.content.res.XmlResourceParser getXml(@NonNull String, @XmlRes int, @Nullable android.content.pm.ApplicationInfo);
     method public boolean hasSigningCertificate(@NonNull String, @NonNull byte[], int);
     method public boolean hasSigningCertificate(int, @NonNull byte[], int);
@@ -12415,7 +12420,7 @@
     method public int addLoader(@NonNull android.content.res.loader.ResourceLoader, @NonNull android.content.res.loader.ResourcesProvider);
     method public final void finishPreloading();
     method public final void flushLayoutCache();
-    method @NonNull public android.content.res.XmlResourceParser getAnimation(@AnimatorRes @AnimRes int) throws android.content.res.Resources.NotFoundException;
+    method @NonNull public android.content.res.XmlResourceParser getAnimation(@AnimRes @AnimatorRes int) throws android.content.res.Resources.NotFoundException;
     method public final android.content.res.AssetManager getAssets();
     method @AnyRes public static int getAttributeSetSourceResId(@Nullable android.util.AttributeSet);
     method public boolean getBoolean(@BoolRes int) throws android.content.res.Resources.NotFoundException;
@@ -13721,10 +13726,10 @@
     method public static android.graphics.Bitmap createBitmap(int, int, @NonNull android.graphics.Bitmap.Config, boolean, @NonNull android.graphics.ColorSpace);
     method public static android.graphics.Bitmap createBitmap(@Nullable android.util.DisplayMetrics, int, int, @NonNull android.graphics.Bitmap.Config, boolean);
     method public static android.graphics.Bitmap createBitmap(@Nullable android.util.DisplayMetrics, int, int, @NonNull android.graphics.Bitmap.Config, boolean, @NonNull android.graphics.ColorSpace);
-    method public static android.graphics.Bitmap createBitmap(@NonNull @ColorInt int[], int, int, int, int, @NonNull android.graphics.Bitmap.Config);
-    method public static android.graphics.Bitmap createBitmap(@NonNull android.util.DisplayMetrics, @NonNull @ColorInt int[], int, int, int, int, @NonNull android.graphics.Bitmap.Config);
-    method public static android.graphics.Bitmap createBitmap(@NonNull @ColorInt int[], int, int, android.graphics.Bitmap.Config);
-    method public static android.graphics.Bitmap createBitmap(@Nullable android.util.DisplayMetrics, @NonNull @ColorInt int[], int, int, @NonNull android.graphics.Bitmap.Config);
+    method public static android.graphics.Bitmap createBitmap(@ColorInt @NonNull int[], int, int, int, int, @NonNull android.graphics.Bitmap.Config);
+    method public static android.graphics.Bitmap createBitmap(@NonNull android.util.DisplayMetrics, @ColorInt @NonNull int[], int, int, int, int, @NonNull android.graphics.Bitmap.Config);
+    method public static android.graphics.Bitmap createBitmap(@ColorInt @NonNull int[], int, int, android.graphics.Bitmap.Config);
+    method public static android.graphics.Bitmap createBitmap(@Nullable android.util.DisplayMetrics, @ColorInt @NonNull int[], int, int, @NonNull android.graphics.Bitmap.Config);
     method @NonNull public static android.graphics.Bitmap createBitmap(@NonNull android.graphics.Picture);
     method @NonNull public static android.graphics.Bitmap createBitmap(@NonNull android.graphics.Picture, int, int, @NonNull android.graphics.Bitmap.Config);
     method public static android.graphics.Bitmap createScaledBitmap(@NonNull android.graphics.Bitmap, int, int, boolean);
@@ -13957,8 +13962,8 @@
     method public void drawDoubleRoundRect(@NonNull android.graphics.RectF, float, float, @NonNull android.graphics.RectF, float, float, @NonNull android.graphics.Paint);
     method public void drawDoubleRoundRect(@NonNull android.graphics.RectF, @NonNull float[], @NonNull android.graphics.RectF, @NonNull float[], @NonNull android.graphics.Paint);
     method public void drawLine(float, float, float, float, @NonNull android.graphics.Paint);
-    method public void drawLines(@Size(multiple=4) @NonNull float[], int, int, @NonNull android.graphics.Paint);
-    method public void drawLines(@Size(multiple=4) @NonNull float[], @NonNull android.graphics.Paint);
+    method public void drawLines(@NonNull @Size(multiple=4) float[], int, int, @NonNull android.graphics.Paint);
+    method public void drawLines(@NonNull @Size(multiple=4) float[], @NonNull android.graphics.Paint);
     method public void drawOval(@NonNull android.graphics.RectF, @NonNull android.graphics.Paint);
     method public void drawOval(float, float, float, float, @NonNull android.graphics.Paint);
     method public void drawPaint(@NonNull android.graphics.Paint);
@@ -13968,7 +13973,7 @@
     method public void drawPicture(@NonNull android.graphics.Picture, @NonNull android.graphics.Rect);
     method public void drawPoint(float, float, @NonNull android.graphics.Paint);
     method public void drawPoints(@Size(multiple=2) float[], int, int, @NonNull android.graphics.Paint);
-    method public void drawPoints(@Size(multiple=2) @NonNull float[], @NonNull android.graphics.Paint);
+    method public void drawPoints(@NonNull @Size(multiple=2) float[], @NonNull android.graphics.Paint);
     method @Deprecated public void drawPosText(@NonNull char[], int, int, @NonNull @Size(multiple=2) float[], @NonNull android.graphics.Paint);
     method @Deprecated public void drawPosText(@NonNull String, @NonNull @Size(multiple=2) float[], @NonNull android.graphics.Paint);
     method public void drawRGB(int, int, int);
@@ -14329,10 +14334,10 @@
     method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(@NonNull java.nio.ByteBuffer);
     method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(@NonNull java.io.File);
     method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(@NonNull java.util.concurrent.Callable<android.content.res.AssetFileDescriptor>);
-    method @WorkerThread @NonNull public static android.graphics.Bitmap decodeBitmap(@NonNull android.graphics.ImageDecoder.Source, @NonNull android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
-    method @WorkerThread @NonNull public static android.graphics.Bitmap decodeBitmap(@NonNull android.graphics.ImageDecoder.Source) throws java.io.IOException;
-    method @WorkerThread @NonNull public static android.graphics.drawable.Drawable decodeDrawable(@NonNull android.graphics.ImageDecoder.Source, @NonNull android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
-    method @WorkerThread @NonNull public static android.graphics.drawable.Drawable decodeDrawable(@NonNull android.graphics.ImageDecoder.Source) throws java.io.IOException;
+    method @NonNull @WorkerThread public static android.graphics.Bitmap decodeBitmap(@NonNull android.graphics.ImageDecoder.Source, @NonNull android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
+    method @NonNull @WorkerThread public static android.graphics.Bitmap decodeBitmap(@NonNull android.graphics.ImageDecoder.Source) throws java.io.IOException;
+    method @NonNull @WorkerThread public static android.graphics.drawable.Drawable decodeDrawable(@NonNull android.graphics.ImageDecoder.Source, @NonNull android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
+    method @NonNull @WorkerThread public static android.graphics.drawable.Drawable decodeDrawable(@NonNull android.graphics.ImageDecoder.Source) throws java.io.IOException;
     method public int getAllocator();
     method @Nullable public android.graphics.Rect getCrop();
     method public int getMemorySizePolicy();
@@ -14351,7 +14356,7 @@
     method public void setPostProcessor(@Nullable android.graphics.PostProcessor);
     method public void setTargetColorSpace(android.graphics.ColorSpace);
     method public void setTargetSampleSize(@IntRange(from=1) int);
-    method public void setTargetSize(@Px @IntRange(from=1) int, @Px @IntRange(from=1) int);
+    method public void setTargetSize(@IntRange(from=1) @Px int, @IntRange(from=1) @Px int);
     method public void setUnpremultipliedRequired(boolean);
     field public static final int ALLOCATOR_DEFAULT = 0; // 0x0
     field public static final int ALLOCATOR_HARDWARE = 3; // 0x3
@@ -14458,8 +14463,8 @@
   }
 
   public class LinearGradient extends android.graphics.Shader {
-    ctor public LinearGradient(float, float, float, float, @NonNull @ColorInt int[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
-    ctor public LinearGradient(float, float, float, float, @NonNull @ColorLong long[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
+    ctor public LinearGradient(float, float, float, float, @ColorInt @NonNull int[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
+    ctor public LinearGradient(float, float, float, float, @ColorLong @NonNull long[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
     ctor public LinearGradient(float, float, float, float, @ColorInt int, @ColorInt int, @NonNull android.graphics.Shader.TileMode);
     ctor public LinearGradient(float, float, float, float, @ColorLong long, @ColorLong long, @NonNull android.graphics.Shader.TileMode);
   }
@@ -15002,8 +15007,8 @@
   }
 
   public class RadialGradient extends android.graphics.Shader {
-    ctor public RadialGradient(float, float, float, @NonNull @ColorInt int[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
-    ctor public RadialGradient(float, float, float, @NonNull @ColorLong long[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
+    ctor public RadialGradient(float, float, float, @ColorInt @NonNull int[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
+    ctor public RadialGradient(float, float, float, @ColorLong @NonNull long[], @Nullable float[], @NonNull android.graphics.Shader.TileMode);
     ctor public RadialGradient(float, float, float, @ColorInt int, @ColorInt int, @NonNull android.graphics.Shader.TileMode);
     ctor public RadialGradient(float, float, float, @ColorLong long, @ColorLong long, @NonNull android.graphics.Shader.TileMode);
   }
@@ -15261,8 +15266,8 @@
   }
 
   public class SweepGradient extends android.graphics.Shader {
-    ctor public SweepGradient(float, float, @NonNull @ColorInt int[], @Nullable float[]);
-    ctor public SweepGradient(float, float, @NonNull @ColorLong long[], @Nullable float[]);
+    ctor public SweepGradient(float, float, @ColorInt @NonNull int[], @Nullable float[]);
+    ctor public SweepGradient(float, float, @ColorLong @NonNull long[], @Nullable float[]);
     ctor public SweepGradient(float, float, @ColorInt int, @ColorInt int);
     ctor public SweepGradient(float, float, @ColorLong long, @ColorLong long);
   }
@@ -15655,8 +15660,8 @@
     method public void setColor(@ColorInt int);
     method public void setColor(@Nullable android.content.res.ColorStateList);
     method public void setColorFilter(@Nullable android.graphics.ColorFilter);
-    method public void setColors(@Nullable @ColorInt int[]);
-    method public void setColors(@Nullable @ColorInt int[], @Nullable float[]);
+    method public void setColors(@ColorInt @Nullable int[]);
+    method public void setColors(@ColorInt @Nullable int[], @Nullable float[]);
     method public void setCornerRadii(@Nullable float[]);
     method public void setCornerRadius(float);
     method public void setDither(boolean);
@@ -16104,14 +16109,14 @@
 
   public static class LineBreaker.ParagraphConstraints {
     ctor public LineBreaker.ParagraphConstraints();
-    method @Px @FloatRange(from=0) public float getDefaultTabStop();
-    method @Px @FloatRange(from=0.0f) public float getFirstWidth();
-    method @Px @IntRange(from=0) public int getFirstWidthLineCount();
+    method @FloatRange(from=0) @Px public float getDefaultTabStop();
+    method @FloatRange(from=0.0f) @Px public float getFirstWidth();
+    method @IntRange(from=0) @Px public int getFirstWidthLineCount();
     method @Nullable public float[] getTabStops();
-    method @Px @FloatRange(from=0.0f) public float getWidth();
-    method public void setIndent(@Px @FloatRange(from=0.0f) float, @Px @IntRange(from=0) int);
-    method public void setTabStops(@Nullable float[], @Px @FloatRange(from=0) float);
-    method public void setWidth(@Px @FloatRange(from=0.0f) float);
+    method @FloatRange(from=0.0f) @Px public float getWidth();
+    method public void setIndent(@FloatRange(from=0.0f) @Px float, @IntRange(from=0) @Px int);
+    method public void setTabStops(@Nullable float[], @FloatRange(from=0) @Px float);
+    method public void setWidth(@FloatRange(from=0.0f) @Px float);
   }
 
   public static class LineBreaker.Result {
@@ -16134,7 +16139,7 @@
   public static final class MeasuredText.Builder {
     ctor public MeasuredText.Builder(@NonNull char[]);
     ctor public MeasuredText.Builder(@NonNull android.graphics.text.MeasuredText);
-    method @NonNull public android.graphics.text.MeasuredText.Builder appendReplacementRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, @Px @FloatRange(from=0) float);
+    method @NonNull public android.graphics.text.MeasuredText.Builder appendReplacementRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, @FloatRange(from=0) @Px float);
     method @NonNull public android.graphics.text.MeasuredText.Builder appendStyleRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, boolean);
     method @NonNull public android.graphics.text.MeasuredText build();
     method @NonNull public android.graphics.text.MeasuredText.Builder setComputeHyphenation(boolean);
@@ -16855,6 +16860,7 @@
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Rational> CONTROL_AE_COMPENSATION_STEP;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> CONTROL_AE_LOCK_AVAILABLE;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AF_AVAILABLE_MODES;
+    field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.CapabilityAndMaxSize[]> CONTROL_AVAILABLE_BOKEH_CAPABILITIES;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_EFFECTS;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_MODES;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_SCENE_MODES;
@@ -17070,6 +17076,9 @@
     field public static final int CONTROL_AWB_STATE_INACTIVE = 0; // 0x0
     field public static final int CONTROL_AWB_STATE_LOCKED = 3; // 0x3
     field public static final int CONTROL_AWB_STATE_SEARCHING = 1; // 0x1
+    field public static final int CONTROL_BOKEH_MODE_CONTINUOUS = 2; // 0x2
+    field public static final int CONTROL_BOKEH_MODE_OFF = 0; // 0x0
+    field public static final int CONTROL_BOKEH_MODE_STILL_CAPTURE = 1; // 0x1
     field public static final int CONTROL_CAPTURE_INTENT_CUSTOM = 0; // 0x0
     field public static final int CONTROL_CAPTURE_INTENT_MANUAL = 6; // 0x6
     field public static final int CONTROL_CAPTURE_INTENT_MOTION_TRACKING = 7; // 0x7
@@ -17265,6 +17274,7 @@
     field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> CONTROL_AWB_LOCK;
     field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_AWB_MODE;
     field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AWB_REGIONS;
+    field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_BOKEH_MODE;
     field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_CAPTURE_INTENT;
     field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_EFFECT_MODE;
     field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> CONTROL_ENABLE_ZSL;
@@ -17350,6 +17360,7 @@
     field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AWB_MODE;
     field @NonNull public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AWB_REGIONS;
     field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AWB_STATE;
+    field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_BOKEH_MODE;
     field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_CAPTURE_INTENT;
     field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_EFFECT_MODE;
     field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Boolean> CONTROL_ENABLE_ZSL;
@@ -17446,6 +17457,11 @@
     field public static final int COUNT = 4; // 0x4
   }
 
+  public final class CapabilityAndMaxSize {
+    method @NonNull public android.util.Size getMaxStreamingSize();
+    method public int getMode();
+  }
+
   public final class ColorSpaceTransform {
     ctor public ColorSpaceTransform(android.util.Rational[]);
     ctor public ColorSpaceTransform(int[]);
@@ -23153,7 +23169,7 @@
     method @Nullable public String getGnssHardwareModelName();
     method public int getGnssYearOfHardware();
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.location.GpsStatus getGpsStatus(@Nullable android.location.GpsStatus);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) @Nullable public android.location.Location getLastKnownLocation(@NonNull String);
+    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.location.Location getLastKnownLocation(@NonNull String);
     method @Nullable public android.location.LocationProvider getProvider(@NonNull String);
     method @NonNull public java.util.List<java.lang.String> getProviders(boolean);
     method @NonNull public java.util.List<java.lang.String> getProviders(@NonNull android.location.Criteria, boolean);
@@ -28624,17 +28640,17 @@
     method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
     method public boolean bindProcessToNetwork(@Nullable android.net.Network);
     method @NonNull public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull android.net.IpSecManager.UdpEncapsulationSocket, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @Nullable public android.net.Network getActiveNetwork();
+    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network getActiveNetwork();
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getActiveNetworkInfo();
     method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo[] getAllNetworkInfo();
-    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @NonNull public android.net.Network[] getAllNetworks();
+    method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network[] getAllNetworks();
     method @Deprecated public boolean getBackgroundDataSetting();
     method @Nullable public android.net.Network getBoundNetworkForProcess();
     method public int getConnectionOwnerUid(int, @NonNull java.net.InetSocketAddress, @NonNull java.net.InetSocketAddress);
     method @Nullable public android.net.ProxyInfo getDefaultProxy();
-    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @Nullable public android.net.LinkProperties getLinkProperties(@Nullable android.net.Network);
+    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.LinkProperties getLinkProperties(@Nullable android.net.Network);
     method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getMultipathPreference(@Nullable android.net.Network);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) @Nullable public android.net.NetworkCapabilities getNetworkCapabilities(@Nullable android.net.Network);
+    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkCapabilities getNetworkCapabilities(@Nullable android.net.Network);
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(int);
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(@Nullable android.net.Network);
     method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getNetworkPreference();
@@ -29770,6 +29786,7 @@
 
   public class ScanResult implements android.os.Parcelable {
     method public int describeContents();
+    method public int getWifiStandard();
     method public boolean is80211mcResponder();
     method public boolean isPasspointNetwork();
     method public void writeToParcel(android.os.Parcel, int);
@@ -29780,6 +29797,11 @@
     field public static final int CHANNEL_WIDTH_80MHZ = 2; // 0x2
     field public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; // 0x4
     field public String SSID;
+    field public static final int WIFI_STANDARD_11AC = 5; // 0x5
+    field public static final int WIFI_STANDARD_11AX = 6; // 0x6
+    field public static final int WIFI_STANDARD_11N = 4; // 0x4
+    field public static final int WIFI_STANDARD_LEGACY = 1; // 0x1
+    field public static final int WIFI_STANDARD_UNKNOWN = 0; // 0x0
     field public String capabilities;
     field public int centerFreq0;
     field public int centerFreq1;
@@ -29976,16 +29998,11 @@
     method public String getSSID();
     method public android.net.wifi.SupplicantState getSupplicantState();
     method @IntRange(from=0xffffffff) public int getTxLinkSpeedMbps();
-    method public int getWifiTechnology();
+    method public int getWifiStandard();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final String FREQUENCY_UNITS = "MHz";
     field public static final String LINK_SPEED_UNITS = "Mbps";
     field public static final int LINK_SPEED_UNKNOWN = -1; // 0xffffffff
-    field public static final int WIFI_TECHNOLOGY_11AC = 5; // 0x5
-    field public static final int WIFI_TECHNOLOGY_11AX = 6; // 0x6
-    field public static final int WIFI_TECHNOLOGY_11N = 4; // 0x4
-    field public static final int WIFI_TECHNOLOGY_LEGACY = 1; // 0x1
-    field public static final int WIFI_TECHNOLOGY_UNKNOWN = 0; // 0x0
   }
 
   public class WifiManager {
@@ -30006,7 +30023,7 @@
     method public android.net.wifi.WifiInfo getConnectionInfo();
     method public android.net.DhcpInfo getDhcpInfo();
     method public int getMaxNumberOfNetworkSuggestionsPerApp();
-    method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) @NonNull public java.util.List<android.net.wifi.WifiNetworkSuggestion> getNetworkSuggestions();
+    method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public java.util.List<android.net.wifi.WifiNetworkSuggestion> getNetworkSuggestions();
     method @Deprecated @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", "android.permission.NETWORK_SETUP_WIZARD"}) public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
     method public java.util.List<android.net.wifi.ScanResult> getScanResults();
     method public int getWifiState();
@@ -30033,7 +30050,7 @@
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
     method public void setTdlsEnabledWithMacAddress(String, boolean);
     method @Deprecated public boolean setWifiEnabled(boolean);
-    method public void startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback, @Nullable android.os.Handler);
+    method @RequiresPermission(allOf={android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback, @Nullable android.os.Handler);
     method @Deprecated public boolean startScan();
     method @Deprecated public void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback);
     method @Deprecated public int updateNetwork(android.net.wifi.WifiConfiguration);
@@ -30343,6 +30360,8 @@
     method public int describeContents();
     method public android.net.wifi.hotspot2.pps.Credential getCredential();
     method public android.net.wifi.hotspot2.pps.HomeSp getHomeSp();
+    method public long getSubscriptionExpirationTimeInMillis();
+    method public boolean isOsuProvisioned();
     method public void setCredential(android.net.wifi.hotspot2.pps.Credential);
     method public void setHomeSp(android.net.wifi.hotspot2.pps.HomeSp);
     method public void writeToParcel(android.os.Parcel, int);
@@ -30955,10 +30974,10 @@
     method public boolean isDefaultServiceForCategory(android.content.ComponentName, String);
     method public boolean registerAidsForService(android.content.ComponentName, String, java.util.List<java.lang.String>);
     method public boolean removeAidsForService(android.content.ComponentName, String);
-    method @RequiresPermission(android.Manifest.permission.NFC) @NonNull public boolean setOffHostForService(@NonNull android.content.ComponentName, @NonNull String);
+    method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean setOffHostForService(@NonNull android.content.ComponentName, @NonNull String);
     method public boolean setPreferredService(android.app.Activity, android.content.ComponentName);
     method public boolean supportsAidPrefixRegistration();
-    method @RequiresPermission(android.Manifest.permission.NFC) @NonNull public boolean unsetOffHostForService(@NonNull android.content.ComponentName);
+    method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean unsetOffHostForService(@NonNull android.content.ComponentName);
     method public boolean unsetPreferredService(android.app.Activity);
     field public static final String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
     field public static final String CATEGORY_OTHER = "other";
@@ -34614,7 +34633,7 @@
     method public void addData(String, byte[], int);
     method public void addFile(String, java.io.File, int) throws java.io.IOException;
     method public void addText(String, String);
-    method @RequiresPermission(allOf={android.Manifest.permission.READ_LOGS, android.Manifest.permission.PACKAGE_USAGE_STATS}) @Nullable public android.os.DropBoxManager.Entry getNextEntry(String, long);
+    method @Nullable @RequiresPermission(allOf={android.Manifest.permission.READ_LOGS, android.Manifest.permission.PACKAGE_USAGE_STATS}) public android.os.DropBoxManager.Entry getNextEntry(String, long);
     method public boolean isTagEnabled(String);
     field public static final String ACTION_DROPBOX_ENTRY_ADDED = "android.intent.action.DROPBOX_ENTRY_ADDED";
     field public static final String EXTRA_DROPPED_COUNT = "android.os.extra.DROPPED_COUNT";
@@ -35500,7 +35519,7 @@
     method public String getUserName();
     method public java.util.List<android.os.UserHandle> getUserProfiles();
     method public android.os.Bundle getUserRestrictions();
-    method public android.os.Bundle getUserRestrictions(android.os.UserHandle);
+    method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.INTERACT_ACROSS_USERS"}, conditional=true) public android.os.Bundle getUserRestrictions(android.os.UserHandle);
     method public boolean hasUserRestriction(String);
     method public boolean isDemoUser();
     method public boolean isQuietModeEnabled(android.os.UserHandle);
@@ -38485,7 +38504,11 @@
     method @NonNull public static String getVersion(@NonNull android.content.Context, @NonNull String);
     method @NonNull public static String getVolumeName(@NonNull android.net.Uri);
     method @NonNull public static android.net.Uri setIncludePending(@NonNull android.net.Uri);
+    method @NonNull public static android.net.Uri setIncludeTrashed(@NonNull android.net.Uri);
     method @NonNull public static android.net.Uri setRequireOriginal(@NonNull android.net.Uri);
+    method public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri);
+    method public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri, long);
+    method public static void untrash(@NonNull android.content.Context, @NonNull android.net.Uri);
     field public static final String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
     field public static final String ACTION_IMAGE_CAPTURE_SECURE = "android.media.action.IMAGE_CAPTURE_SECURE";
     field public static final String ACTION_REVIEW = "android.provider.action.REVIEW";
@@ -38578,14 +38601,11 @@
   }
 
   public static interface MediaStore.Audio.AudioColumns extends android.provider.MediaStore.MediaColumns {
-    field public static final String ALBUM = "album";
     field public static final String ALBUM_ID = "album_id";
     field @Deprecated public static final String ALBUM_KEY = "album_key";
-    field public static final String ARTIST = "artist";
     field public static final String ARTIST_ID = "artist_id";
     field @Deprecated public static final String ARTIST_KEY = "artist_key";
     field public static final String BOOKMARK = "bookmark";
-    field public static final String COMPOSER = "composer";
     field public static final String GENRE = "genre";
     field public static final String GENRE_ID = "genre_id";
     field @Deprecated public static final String GENRE_KEY = "genre_key";
@@ -38700,7 +38720,6 @@
     field public static final int MEDIA_TYPE_VIDEO = 3; // 0x3
     field public static final String MIME_TYPE = "mime_type";
     field public static final String PARENT = "parent";
-    field public static final String TITLE = "title";
   }
 
   public static final class MediaStore.Images {
@@ -38709,6 +38728,9 @@
 
   public static interface MediaStore.Images.ImageColumns extends android.provider.MediaStore.MediaColumns {
     field public static final String DESCRIPTION = "description";
+    field public static final String EXPOSURE_TIME = "exposure_time";
+    field public static final String F_NUMBER = "f_number";
+    field public static final String ISO = "iso";
     field public static final String IS_PRIVATE = "isprivate";
     field @Deprecated public static final String LATITUDE = "latitude";
     field @Deprecated public static final String LONGITUDE = "longitude";
@@ -38757,28 +38779,45 @@
   }
 
   public static interface MediaStore.MediaColumns extends android.provider.BaseColumns {
+    field public static final String ALBUM = "album";
+    field public static final String ALBUM_ARTIST = "album_artist";
+    field public static final String ARTIST = "artist";
+    field public static final String AUTHOR = "author";
+    field public static final String BITRATE = "bitrate";
     field public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
     field public static final String BUCKET_ID = "bucket_id";
+    field public static final String CAPTURE_FRAMERATE = "capture_framerate";
+    field public static final String CD_TRACK_NUMBER = "cd_track_number";
+    field public static final String COMPILATION = "compilation";
+    field public static final String COMPOSER = "composer";
     field @Deprecated public static final String DATA = "_data";
     field public static final String DATE_ADDED = "date_added";
     field public static final String DATE_EXPIRES = "date_expires";
     field public static final String DATE_MODIFIED = "date_modified";
     field public static final String DATE_TAKEN = "datetaken";
+    field public static final String DISC_NUMBER = "disc_number";
     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 GENRE = "genre";
     field public static final String HEIGHT = "height";
     field public static final String INSTANCE_ID = "instance_id";
+    field public static final String IS_FAVORITE = "is_favorite";
     field public static final String IS_PENDING = "is_pending";
+    field public static final String IS_TRASHED = "is_trashed";
     field public static final String MIME_TYPE = "mime_type";
+    field public static final String NUM_TRACKS = "num_tracks";
     field public static final String ORIENTATION = "orientation";
     field public static final String ORIGINAL_DOCUMENT_ID = "original_document_id";
     field public static final String OWNER_PACKAGE_NAME = "owner_package_name";
     field public static final String RELATIVE_PATH = "relative_path";
+    field public static final String RESOLUTION = "resolution";
     field public static final String SIZE = "_size";
     field public static final String TITLE = "title";
     field public static final String VOLUME_NAME = "volume_name";
     field public static final String WIDTH = "width";
+    field public static final String WRITER = "writer";
+    field public static final String YEAR = "year";
   }
 
   public static final class MediaStore.Video {
@@ -38818,8 +38857,6 @@
   }
 
   public static interface MediaStore.Video.VideoColumns extends android.provider.MediaStore.MediaColumns {
-    field public static final String ALBUM = "album";
-    field public static final String ARTIST = "artist";
     field public static final String BOOKMARK = "bookmark";
     field public static final String CATEGORY = "category";
     field public static final String COLOR_RANGE = "color_range";
@@ -38831,7 +38868,6 @@
     field @Deprecated public static final String LATITUDE = "latitude";
     field @Deprecated public static final String LONGITUDE = "longitude";
     field @Deprecated public static final String MINI_THUMB_MAGIC = "mini_thumb_magic";
-    field public static final String RESOLUTION = "resolution";
     field public static final String TAGS = "tags";
   }
 
@@ -38914,6 +38950,7 @@
     field public static final String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
     field public static final String ACTION_SETTINGS = "android.settings.SETTINGS";
     field public static final String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
+    field public static final String ACTION_SHOW_WORK_POLICY_INFO = "android.settings.SHOW_WORK_POLICY_INFO";
     field public static final String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
     field @Deprecated public static final String ACTION_STORAGE_VOLUME_ACCESS_SETTINGS = "android.settings.STORAGE_VOLUME_ACCESS_SETTINGS";
     field public static final String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
@@ -44013,7 +44050,7 @@
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getSelfManagedPhoneAccounts();
     method public android.telecom.PhoneAccountHandle getSimCallManager();
     method @Nullable public String getSystemDialerPackage();
-    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @Nullable public android.telecom.PhoneAccountHandle getUserSelectedOutgoingPhoneAccount();
+    method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telecom.PhoneAccountHandle getUserSelectedOutgoingPhoneAccount();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber(android.telecom.PhoneAccountHandle);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handleMmi(String);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handleMmi(String, android.telecom.PhoneAccountHandle);
@@ -44374,6 +44411,7 @@
     field public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT = "opportunistic_network_exit_threshold_rsrp_int";
     field public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT = "opportunistic_network_exit_threshold_rssnr_int";
     field public static final String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
+    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_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
@@ -44941,6 +44979,7 @@
     method public static int getDefaultSmsSubscriptionId();
     method public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int);
     method @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS) public void getSmsMessagesForFinancialApp(android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.SmsManager.FinancialSmsCallback);
+    method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getSmscAddress();
     method public int getSubscriptionId();
     method public void injectSmsPdu(byte[], String, android.app.PendingIntent);
     method public void sendDataMessage(String, String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
@@ -44948,6 +44987,7 @@
     method public void sendMultipartTextMessage(String, String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
     method public void sendTextMessage(String, String, String, android.app.PendingIntent, android.app.PendingIntent);
     method @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.SEND_SMS}) public void sendTextMessageWithoutPersisting(String, String, String, android.app.PendingIntent, android.app.PendingIntent);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setSmscAddress(@NonNull String);
     field public static final String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
     field public static final String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
     field public static final String MMS_CONFIG_ALIAS_ENABLED = "aliasEnabled";
@@ -44989,13 +45029,60 @@
     field public static final int MMS_ERROR_RETRY = 6; // 0x6
     field public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3; // 0x3
     field public static final int MMS_ERROR_UNSPECIFIED = 1; // 0x1
+    field public static final int RESULT_BLUETOOTH_DISCONNECTED = 27; // 0x1b
+    field public static final int RESULT_CANCELLED = 23; // 0x17
+    field public static final int RESULT_ENCODING_ERROR = 18; // 0x12
+    field public static final int RESULT_ERROR_FDN_CHECK_FAILURE = 6; // 0x6
     field public static final int RESULT_ERROR_GENERIC_FAILURE = 1; // 0x1
     field public static final int RESULT_ERROR_LIMIT_EXCEEDED = 5; // 0x5
+    field public static final int RESULT_ERROR_NONE = 0; // 0x0
     field public static final int RESULT_ERROR_NO_SERVICE = 4; // 0x4
     field public static final int RESULT_ERROR_NULL_PDU = 3; // 0x3
     field public static final int RESULT_ERROR_RADIO_OFF = 2; // 0x2
     field public static final int RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED = 8; // 0x8
     field public static final int RESULT_ERROR_SHORT_CODE_NOT_ALLOWED = 7; // 0x7
+    field public static final int RESULT_INTERNAL_ERROR = 21; // 0x15
+    field public static final int RESULT_INVALID_ARGUMENTS = 11; // 0xb
+    field public static final int RESULT_INVALID_BLUETOOTH_ADDRESS = 26; // 0x1a
+    field public static final int RESULT_INVALID_SMSC_ADDRESS = 19; // 0x13
+    field public static final int RESULT_INVALID_SMS_FORMAT = 14; // 0xe
+    field public static final int RESULT_INVALID_STATE = 12; // 0xc
+    field public static final int RESULT_MODEM_ERROR = 16; // 0x10
+    field public static final int RESULT_NETWORK_ERROR = 17; // 0x11
+    field public static final int RESULT_NETWORK_REJECT = 10; // 0xa
+    field public static final int RESULT_NO_BLUETOOTH_SERVICE = 25; // 0x19
+    field public static final int RESULT_NO_DEFAULT_SMS_APP = 32; // 0x20
+    field public static final int RESULT_NO_MEMORY = 13; // 0xd
+    field public static final int RESULT_NO_RESOURCES = 22; // 0x16
+    field public static final int RESULT_OPERATION_NOT_ALLOWED = 20; // 0x14
+    field public static final int RESULT_RADIO_NOT_AVAILABLE = 9; // 0x9
+    field public static final int RESULT_REMOTE_EXCEPTION = 31; // 0x1f
+    field public static final int RESULT_REQUEST_NOT_SUPPORTED = 24; // 0x18
+    field public static final int RESULT_RIL_CANCELLED = 119; // 0x77
+    field public static final int RESULT_RIL_ENCODING_ERR = 109; // 0x6d
+    field public static final int RESULT_RIL_INTERNAL_ERR = 113; // 0x71
+    field public static final int RESULT_RIL_INVALID_ARGUMENTS = 104; // 0x68
+    field public static final int RESULT_RIL_INVALID_MODEM_STATE = 115; // 0x73
+    field public static final int RESULT_RIL_INVALID_SMSC_ADDRESS = 110; // 0x6e
+    field public static final int RESULT_RIL_INVALID_SMS_FORMAT = 107; // 0x6b
+    field public static final int RESULT_RIL_INVALID_STATE = 103; // 0x67
+    field public static final int RESULT_RIL_MODEM_ERR = 111; // 0x6f
+    field public static final int RESULT_RIL_NETWORK_ERR = 112; // 0x70
+    field public static final int RESULT_RIL_NETWORK_NOT_READY = 116; // 0x74
+    field public static final int RESULT_RIL_NETWORK_REJECT = 102; // 0x66
+    field public static final int RESULT_RIL_NO_MEMORY = 105; // 0x69
+    field public static final int RESULT_RIL_NO_RESOURCES = 118; // 0x76
+    field public static final int RESULT_RIL_OPERATION_NOT_ALLOWED = 117; // 0x75
+    field public static final int RESULT_RIL_RADIO_NOT_AVAILABLE = 100; // 0x64
+    field public static final int RESULT_RIL_REQUEST_NOT_SUPPORTED = 114; // 0x72
+    field public static final int RESULT_RIL_REQUEST_RATE_LIMITED = 106; // 0x6a
+    field public static final int RESULT_RIL_SIM_ABSENT = 120; // 0x78
+    field public static final int RESULT_RIL_SMS_SEND_FAIL_RETRY = 101; // 0x65
+    field public static final int RESULT_RIL_SYSTEM_ERR = 108; // 0x6c
+    field public static final int RESULT_SMS_BLOCKED_DURING_EMERGENCY = 29; // 0x1d
+    field public static final int RESULT_SMS_SEND_RETRY_FAILED = 30; // 0x1e
+    field public static final int RESULT_SYSTEM_ERROR = 15; // 0xf
+    field public static final int RESULT_UNEXPECTED_EVENT_STOP_SENDING = 28; // 0x1c
     field public static final int STATUS_ON_ICC_FREE = 0; // 0x0
     field public static final int STATUS_ON_ICC_READ = 1; // 0x1
     field public static final int STATUS_ON_ICC_SENT = 5; // 0x5
@@ -45201,9 +45288,9 @@
     method public int getDataState();
     method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDeviceId();
     method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDeviceId(int);
-    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @Nullable public String getDeviceSoftwareVersion();
-    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @NonNull public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList();
-    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @NonNull public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList(int);
+    method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getDeviceSoftwareVersion();
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList();
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList(int);
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String[] getForbiddenPlmns();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getGroupIdLevel1();
     method public String getIccAuthentication(int, int, String);
@@ -45237,11 +45324,12 @@
     method @Nullable public CharSequence getSimSpecificCarrierIdName();
     method public int getSimState();
     method public int getSimState(int);
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getSubIdForPhoneAccountHandle(@NonNull android.telecom.PhoneAccountHandle);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getSubscriberId();
     method public int getSupportedModemCount();
     method @Nullable public String getTypeAllocationCode();
     method @Nullable public String getTypeAllocationCode(int);
-    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @NonNull public java.util.List<android.telephony.UiccCardInfo> getUiccCardsInfo();
+    method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public java.util.List<android.telephony.UiccCardInfo> getUiccCardsInfo();
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVisualVoicemailPackageName();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailAlphaTag();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber();
@@ -47175,7 +47263,7 @@
   }
 
   public static class LineHeightSpan.Standard implements android.text.style.LineHeightSpan android.text.ParcelableSpan {
-    ctor public LineHeightSpan.Standard(@Px @IntRange(from=1) int);
+    ctor public LineHeightSpan.Standard(@IntRange(from=1) @Px int);
     ctor public LineHeightSpan.Standard(@NonNull android.os.Parcel);
     method public void chooseHeight(@NonNull CharSequence, int, int, int, int, @NonNull android.graphics.Paint.FontMetricsInt);
     method public int describeContents();
@@ -49106,6 +49194,7 @@
 
   public class HapticFeedbackConstants {
     field public static final int CLOCK_TICK = 4; // 0x4
+    field public static final int CONFIRM = 16; // 0x10
     field public static final int CONTEXT_CLICK = 6; // 0x6
     field public static final int FLAG_IGNORE_GLOBAL_SETTING = 2; // 0x2
     field public static final int FLAG_IGNORE_VIEW_SETTING = 1; // 0x1
@@ -49113,6 +49202,7 @@
     field public static final int KEYBOARD_RELEASE = 7; // 0x7
     field public static final int KEYBOARD_TAP = 3; // 0x3
     field public static final int LONG_PRESS = 0; // 0x0
+    field public static final int REJECT = 17; // 0x11
     field public static final int TEXT_HANDLE_MOVE = 9; // 0x9
     field public static final int VIRTUAL_KEY = 1; // 0x1
     field public static final int VIRTUAL_KEY_RELEASE = 8; // 0x8
@@ -51321,11 +51411,11 @@
     field @Deprecated public static final boolean TRACE_RECYCLER = false;
   }
 
-  @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public static @interface ViewDebug.CapturedViewProperty {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface ViewDebug.CapturedViewProperty {
     method public abstract boolean retrieveReturn() default false;
   }
 
-  @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public static @interface ViewDebug.ExportedProperty {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface ViewDebug.ExportedProperty {
     method public abstract String category() default "";
     method public abstract boolean deepExport() default false;
     method public abstract android.view.ViewDebug.FlagToString[] flagMapping() default {};
@@ -51337,7 +51427,7 @@
     method public abstract boolean resolveId() default false;
   }
 
-  @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public static @interface ViewDebug.FlagToString {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface ViewDebug.FlagToString {
     method public abstract int equals();
     method public abstract int mask();
     method public abstract String name();
@@ -51355,7 +51445,7 @@
     enum_constant @Deprecated public static final android.view.ViewDebug.HierarchyTraceType REQUEST_LAYOUT;
   }
 
-  @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public static @interface ViewDebug.IntToString {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface ViewDebug.IntToString {
     method public abstract int from();
     method public abstract String to();
   }
@@ -53913,18 +54003,18 @@
   }
 
   public interface TextClassifier {
-    method @WorkerThread @NonNull public default android.view.textclassifier.TextClassification classifyText(@NonNull android.view.textclassifier.TextClassification.Request);
-    method @WorkerThread @NonNull public default android.view.textclassifier.TextClassification classifyText(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @Nullable android.os.LocaleList);
+    method @NonNull @WorkerThread public default android.view.textclassifier.TextClassification classifyText(@NonNull android.view.textclassifier.TextClassification.Request);
+    method @NonNull @WorkerThread public default android.view.textclassifier.TextClassification classifyText(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @Nullable android.os.LocaleList);
     method public default void destroy();
-    method @WorkerThread @NonNull public default android.view.textclassifier.TextLanguage detectLanguage(@NonNull android.view.textclassifier.TextLanguage.Request);
-    method @WorkerThread @NonNull public default android.view.textclassifier.TextLinks generateLinks(@NonNull android.view.textclassifier.TextLinks.Request);
+    method @NonNull @WorkerThread public default android.view.textclassifier.TextLanguage detectLanguage(@NonNull android.view.textclassifier.TextLanguage.Request);
+    method @NonNull @WorkerThread public default android.view.textclassifier.TextLinks generateLinks(@NonNull android.view.textclassifier.TextLinks.Request);
     method @WorkerThread public default int getMaxGenerateLinksTextLength();
     method public default boolean isDestroyed();
     method public default void onSelectionEvent(@NonNull android.view.textclassifier.SelectionEvent);
     method public default void onTextClassifierEvent(@NonNull android.view.textclassifier.TextClassifierEvent);
-    method @WorkerThread @NonNull public default android.view.textclassifier.ConversationActions suggestConversationActions(@NonNull android.view.textclassifier.ConversationActions.Request);
-    method @WorkerThread @NonNull public default android.view.textclassifier.TextSelection suggestSelection(@NonNull android.view.textclassifier.TextSelection.Request);
-    method @WorkerThread @NonNull public default android.view.textclassifier.TextSelection suggestSelection(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @Nullable android.os.LocaleList);
+    method @NonNull @WorkerThread public default android.view.textclassifier.ConversationActions suggestConversationActions(@NonNull android.view.textclassifier.ConversationActions.Request);
+    method @NonNull @WorkerThread public default android.view.textclassifier.TextSelection suggestSelection(@NonNull android.view.textclassifier.TextSelection.Request);
+    method @NonNull @WorkerThread public default android.view.textclassifier.TextSelection suggestSelection(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @Nullable android.os.LocaleList);
     field public static final String EXTRA_FROM_TEXT_CLASSIFIER = "android.view.textclassifier.extra.FROM_TEXT_CLASSIFIER";
     field public static final String HINT_TEXT_IS_EDITABLE = "android.text_is_editable";
     field public static final String HINT_TEXT_IS_NOT_EDITABLE = "android.text_is_not_editable";
@@ -56388,12 +56478,12 @@
     ctor public Magnifier.Builder(@NonNull android.view.View);
     method @NonNull public android.widget.Magnifier build();
     method @NonNull public android.widget.Magnifier.Builder setClippingEnabled(boolean);
-    method @NonNull public android.widget.Magnifier.Builder setCornerRadius(@Px @FloatRange(from=0) float);
+    method @NonNull public android.widget.Magnifier.Builder setCornerRadius(@FloatRange(from=0) @Px float);
     method @NonNull public android.widget.Magnifier.Builder setDefaultSourceToMagnifierOffset(@Px int, @Px int);
-    method @NonNull public android.widget.Magnifier.Builder setElevation(@Px @FloatRange(from=0) float);
+    method @NonNull public android.widget.Magnifier.Builder setElevation(@FloatRange(from=0) @Px float);
     method @NonNull public android.widget.Magnifier.Builder setInitialZoom(@FloatRange(from=0.0f) float);
     method @NonNull public android.widget.Magnifier.Builder setOverlay(@Nullable android.graphics.drawable.Drawable);
-    method @NonNull public android.widget.Magnifier.Builder setSize(@Px @IntRange(from=0) int, @Px @IntRange(from=0) int);
+    method @NonNull public android.widget.Magnifier.Builder setSize(@IntRange(from=0) @Px int, @IntRange(from=0) @Px int);
     method @NonNull public android.widget.Magnifier.Builder setSourceBounds(int, int, int, int);
   }
 
@@ -56887,7 +56977,7 @@
     method @NonNull public static android.widget.RemoteViews.RemoteResponse fromPendingIntent(@NonNull android.app.PendingIntent);
   }
 
-  @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public static @interface RemoteViews.RemoteView {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface RemoteViews.RemoteView {
   }
 
   public abstract class RemoteViewsService extends android.app.Service {
@@ -57564,7 +57654,7 @@
     method public void setExtractedText(android.view.inputmethod.ExtractedText);
     method public void setFallbackLineSpacing(boolean);
     method public void setFilters(android.text.InputFilter[]);
-    method public void setFirstBaselineToTopHeight(@Px @IntRange(from=0) int);
+    method public void setFirstBaselineToTopHeight(@IntRange(from=0) @Px int);
     method public void setFontFeatureSettings(@Nullable String);
     method public boolean setFontVariationSettings(@Nullable String);
     method protected boolean setFrame(int, int, int, int);
@@ -57586,9 +57676,9 @@
     method public void setInputType(int);
     method public void setJustificationMode(int);
     method public void setKeyListener(android.text.method.KeyListener);
-    method public void setLastBaselineToBottomHeight(@Px @IntRange(from=0) int);
+    method public void setLastBaselineToBottomHeight(@IntRange(from=0) @Px int);
     method public void setLetterSpacing(float);
-    method public void setLineHeight(@Px @IntRange(from=0) int);
+    method public void setLineHeight(@IntRange(from=0) @Px int);
     method public void setLineSpacing(float, float);
     method public void setLines(int);
     method public final void setLinkTextColor(@ColorInt int);
@@ -60643,7 +60733,7 @@
     ctor public OutOfMemoryError(String);
   }
 
-  @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public @interface Override {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) public @interface Override {
   }
 
   public class Package implements java.lang.reflect.AnnotatedElement {
@@ -61135,9 +61225,9 @@
     method @NonNull public StringBuilder reverse();
     method public void setCharAt(int, char);
     method public void setLength(int);
-    method public CharSequence subSequence(int, int);
-    method public String substring(int);
-    method public String substring(int, int);
+    method @NonNull public CharSequence subSequence(int, int);
+    method @NonNull public String substring(int);
+    method @NonNull public String substring(int, int);
     method public void trimToSize();
   }
 
@@ -61147,7 +61237,7 @@
     ctor public StringIndexOutOfBoundsException(int);
   }
 
-  @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.LOCAL_VARIABLE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public @interface SuppressWarnings {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.LOCAL_VARIABLE}) public @interface SuppressWarnings {
     method public abstract String[] value();
   }
 
@@ -71470,20 +71560,20 @@
     method public boolean addAll(@NonNull java.util.Collection<? extends K>);
     method public final void clear();
     method public boolean contains(@NonNull Object);
-    method public final boolean containsAll(java.util.Collection<?>);
+    method public final boolean containsAll(@NonNull java.util.Collection<?>);
     method public void forEach(@NonNull java.util.function.Consumer<? super K>);
-    method public java.util.concurrent.ConcurrentHashMap<K,V> getMap();
+    method @NonNull public java.util.concurrent.ConcurrentHashMap<K,V> getMap();
     method @Nullable public V getMappedValue();
     method public final boolean isEmpty();
     method @NonNull public java.util.Iterator<K> iterator();
     method public boolean remove(@NonNull Object);
-    method public final boolean removeAll(java.util.Collection<?>);
-    method public final boolean retainAll(java.util.Collection<?>);
+    method public final boolean removeAll(@NonNull java.util.Collection<?>);
+    method public final boolean retainAll(@NonNull java.util.Collection<?>);
     method public final int size();
     method @NonNull public java.util.Spliterator<K> spliterator();
-    method public final Object[] toArray();
-    method public final <T> T[] toArray(T[]);
-    method public final String toString();
+    method @NonNull public final Object[] toArray();
+    method @NonNull public final <T> T[] toArray(@NonNull T[]);
+    method @NonNull public final String toString();
   }
 
   public class ConcurrentLinkedDeque<E> extends java.util.AbstractCollection<E> implements java.util.Deque<E> java.io.Serializable {
diff --git a/api/removed.txt b/api/removed.txt
index 74a9346..a395cc7 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -444,13 +444,12 @@
     method @Deprecated @NonNull public static android.net.Uri createPending(@NonNull android.content.Context, @NonNull android.provider.MediaStore.PendingParams);
     method @Deprecated @NonNull public static java.util.Set<java.lang.String> getAllVolumeNames(@NonNull android.content.Context);
     method @Deprecated @NonNull public static android.provider.MediaStore.PendingSession openPending(@NonNull android.content.Context, @NonNull android.net.Uri);
-    method @Deprecated @NonNull public static android.net.Uri setIncludeTrashed(@NonNull android.net.Uri);
-    method @Deprecated public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri);
-    method @Deprecated public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri, long);
-    method @Deprecated public static void untrash(@NonNull android.content.Context, @NonNull android.net.Uri);
   }
 
   public static interface MediaStore.Audio.AudioColumns extends android.provider.MediaStore.MediaColumns {
+    field public static final String ALBUM = "album";
+    field public static final String ARTIST = "artist";
+    field public static final String COMPOSER = "composer";
     field public static final String DURATION = "duration";
   }
 
@@ -458,6 +457,10 @@
     field @Deprecated public static final String DESCRIPTION = "description";
   }
 
+  public static interface MediaStore.Files.FileColumns extends android.provider.MediaStore.MediaColumns {
+    field public static final String TITLE = "title";
+  }
+
   public static interface MediaStore.Images.ImageColumns extends android.provider.MediaStore.MediaColumns {
     field public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
     field public static final String BUCKET_ID = "bucket_id";
@@ -468,10 +471,6 @@
 
   public static interface MediaStore.MediaColumns extends android.provider.BaseColumns {
     field @Deprecated public static final String GROUP_ID = "group_id";
-    field @Deprecated public static final String HASH = "_hash";
-    field @Deprecated public static final String IS_TRASHED = "is_trashed";
-    field @Deprecated public static final String PRIMARY_DIRECTORY = "primary_directory";
-    field @Deprecated public static final String SECONDARY_DIRECTORY = "secondary_directory";
   }
 
   @Deprecated public static class MediaStore.PendingParams {
@@ -491,11 +490,14 @@
   }
 
   public static interface MediaStore.Video.VideoColumns extends android.provider.MediaStore.MediaColumns {
+    field public static final String ALBUM = "album";
+    field public static final String ARTIST = "artist";
     field public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
     field public static final String BUCKET_ID = "bucket_id";
     field public static final String DATE_TAKEN = "datetaken";
     field public static final String DURATION = "duration";
     field public static final String GROUP_ID = "group_id";
+    field public static final String RESOLUTION = "resolution";
   }
 
   public static final class Settings.Global extends android.provider.Settings.NameValueTable {
diff --git a/api/system-current.txt b/api/system-current.txt
index ad9a04d..9a241e8 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -75,6 +75,7 @@
     field public static final String GET_TOP_ACTIVITY_INFO = "android.permission.GET_TOP_ACTIVITY_INFO";
     field public static final String GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS = "android.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS";
     field public static final String GRANT_RUNTIME_PERMISSIONS = "android.permission.GRANT_RUNTIME_PERMISSIONS";
+    field public static final String GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS = "android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS";
     field public static final String HARDWARE_TEST = "android.permission.HARDWARE_TEST";
     field public static final String HDMI_CEC = "android.permission.HDMI_CEC";
     field public static final String HIDE_NON_SYSTEM_OVERLAY_WINDOWS = "android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS";
@@ -391,7 +392,7 @@
     field public static final int UID_STATE_CACHED = 700; // 0x2bc
     field public static final int UID_STATE_FOREGROUND = 500; // 0x1f4
     field public static final int UID_STATE_FOREGROUND_SERVICE = 400; // 0x190
-    field public static final int UID_STATE_FOREGROUND_SERVICE_LOCATION = 300; // 0x12c
+    field @Deprecated public static final int UID_STATE_FOREGROUND_SERVICE_LOCATION = 300; // 0x12c
     field public static final int UID_STATE_PERSISTENT = 100; // 0x64
     field public static final int UID_STATE_TOP = 200; // 0xc8
   }
@@ -602,7 +603,7 @@
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getStatsMetadata() throws android.app.StatsManager.StatsUnavailableException;
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void removeConfig(long) throws android.app.StatsManager.StatsUnavailableException;
     method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean removeConfiguration(long);
-    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) @NonNull public long[] setActiveConfigsChangedOperation(@Nullable android.app.PendingIntent) throws android.app.StatsManager.StatsUnavailableException;
+    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public long[] setActiveConfigsChangedOperation(@Nullable android.app.PendingIntent) throws android.app.StatsManager.StatsUnavailableException;
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void setBroadcastSubscriber(android.app.PendingIntent, long, long) throws android.app.StatsManager.StatsUnavailableException;
     method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
     method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean setDataFetchOperation(long, android.app.PendingIntent);
@@ -1391,9 +1392,10 @@
     method public abstract void sendBroadcast(android.content.Intent, @Nullable String, @Nullable android.os.Bundle);
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, @Nullable android.os.Bundle);
     method public abstract void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
-    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public void startActivityAsUser(@RequiresPermission @NonNull android.content.Intent, @NonNull android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle);
     field public static final String APP_PREDICTION_SERVICE = "app_prediction";
     field public static final String BACKUP_SERVICE = "backup";
+    field public static final String BATTERY_STATS_SERVICE = "batterystats";
     field public static final String BUGREPORT_SERVICE = "bugreport";
     field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
     field public static final String CONTEXTHUB_SERVICE = "contexthub";
@@ -1883,8 +1885,8 @@
 
   public final class RollbackManager {
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, "android.permission.TEST_MANAGE_ROLLBACKS"}) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
-    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, "android.permission.TEST_MANAGE_ROLLBACKS"}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
-    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, "android.permission.TEST_MANAGE_ROLLBACKS"}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, "android.permission.TEST_MANAGE_ROLLBACKS"}) public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, "android.permission.TEST_MANAGE_ROLLBACKS"}) public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
     field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS";
     field public static final String EXTRA_STATUS_MESSAGE = "android.content.rollback.extra.STATUS_MESSAGE";
     field public static final int STATUS_FAILURE = 1; // 0x1
@@ -2395,24 +2397,24 @@
   }
 
   public final class ContextHubManager {
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.ContextHubClientCallback, @NonNull java.util.concurrent.Executor);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.ContextHubClientCallback);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.app.PendingIntent, long);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubTransaction<java.lang.Void> disableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubTransaction<java.lang.Void> enableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.ContextHubClientCallback, @NonNull java.util.concurrent.Executor);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.ContextHubClientCallback);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.app.PendingIntent, long);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubTransaction<java.lang.Void> disableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubTransaction<java.lang.Void> enableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
     method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int[] findNanoAppOnHub(int, @NonNull android.hardware.location.NanoAppFilter);
     method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int[] getContextHubHandles();
     method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubInfo getContextHubInfo(int);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public java.util.List<android.hardware.location.ContextHubInfo> getContextHubs();
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public java.util.List<android.hardware.location.ContextHubInfo> getContextHubs();
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int loadNanoApp(int, @NonNull android.hardware.location.NanoApp);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubTransaction<java.lang.Void> loadNanoApp(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.NanoAppBinary);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubTransaction<java.util.List<android.hardware.location.NanoAppState>> queryNanoApps(@NonNull android.hardware.location.ContextHubInfo);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubTransaction<java.lang.Void> loadNanoApp(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.NanoAppBinary);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubTransaction<java.util.List<android.hardware.location.NanoAppState>> queryNanoApps(@NonNull android.hardware.location.ContextHubInfo);
     method @Deprecated public int registerCallback(@NonNull android.hardware.location.ContextHubManager.Callback);
     method @Deprecated public int registerCallback(android.hardware.location.ContextHubManager.Callback, android.os.Handler);
     method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int sendMessage(int, int, @NonNull android.hardware.location.ContextHubMessage);
     method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int unloadNanoApp(int);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) @NonNull public android.hardware.location.ContextHubTransaction<java.lang.Void> unloadNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.hardware.location.ContextHubTransaction<java.lang.Void> unloadNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
     method @Deprecated public int unregisterCallback(@NonNull android.hardware.location.ContextHubManager.Callback);
     field public static final int EVENT_HUB_RESET = 6; // 0x6
     field public static final int EVENT_NANOAPP_ABORTED = 4; // 0x4
@@ -3098,7 +3100,7 @@
   }
 
   public final class UsbPort {
-    method @RequiresPermission(android.Manifest.permission.MANAGE_USB) @Nullable public android.hardware.usb.UsbPortStatus getStatus();
+    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USB) public android.hardware.usb.UsbPortStatus getStatus();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setRoles(int, int);
   }
 
@@ -3479,7 +3481,8 @@
     method @NonNull public static android.location.LocationRequest createFromDeprecatedCriteria(@NonNull android.location.Criteria, long, float, boolean);
     method @NonNull public static android.location.LocationRequest createFromDeprecatedProvider(@NonNull String, long, float, boolean);
     method public int describeContents();
-    method public long getExpireAt();
+    method @Deprecated public long getExpireAt();
+    method public long getExpireIn();
     method public long getFastestInterval();
     method public boolean getHideFromAppOps();
     method public long getInterval();
@@ -3490,12 +3493,12 @@
     method @Nullable public android.os.WorkSource getWorkSource();
     method public boolean isLocationSettingsIgnored();
     method public boolean isLowPowerMode();
-    method @NonNull public android.location.LocationRequest setExpireAt(long);
+    method @Deprecated @NonNull public android.location.LocationRequest setExpireAt(long);
     method @NonNull public android.location.LocationRequest setExpireIn(long);
     method @NonNull public android.location.LocationRequest setFastestInterval(long);
     method public void setHideFromAppOps(boolean);
     method @NonNull public android.location.LocationRequest setInterval(long);
-    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @NonNull public android.location.LocationRequest setLocationSettingsIgnored(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
     method @NonNull public android.location.LocationRequest setLowPowerMode(boolean);
     method @NonNull public android.location.LocationRequest setNumUpdates(int);
     method @NonNull public android.location.LocationRequest setProvider(@NonNull String);
@@ -3638,7 +3641,7 @@
   public final class MediaRecorder.AudioSource {
     field @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT) public static final int ECHO_REFERENCE = 1997; // 0x7cd
     field @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_HOTWORD) public static final int HOTWORD = 1999; // 0x7cf
-    field public static final int RADIO_TUNER = 1998; // 0x7ce
+    field @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT) public static final int RADIO_TUNER = 1998; // 0x7ce
   }
 
   public class PlayerProxy {
@@ -3826,7 +3829,7 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public void deleteModel(java.util.UUID);
     method public int getDetectionServiceOperationsTimeout();
     method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.media.soundtrigger.SoundTriggerManager.Model getModel(java.util.UUID);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) @Nullable public android.hardware.soundtrigger.SoundTrigger.ModuleProperties getModuleProperties();
+    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.hardware.soundtrigger.SoundTrigger.ModuleProperties getModuleProperties();
     method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public void updateModel(android.media.soundtrigger.SoundTriggerManager.Model);
   }
 
@@ -4514,7 +4517,8 @@
     method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException;
     method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
     method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int);
-    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
+    method @Deprecated @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
+    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int, @NonNull byte[]);
   }
 
 }
@@ -4733,10 +4737,37 @@
     field @Deprecated public byte id;
   }
 
+  public final class SoftApConfiguration implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public android.net.MacAddress getBssid();
+    method @Nullable public String getSsid();
+    method @Nullable public String getWpa2Passphrase();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApConfiguration> CREATOR;
+  }
+
+  public static final class SoftApConfiguration.Builder {
+    ctor public SoftApConfiguration.Builder();
+    ctor public SoftApConfiguration.Builder(@NonNull android.net.wifi.SoftApConfiguration);
+    method @NonNull public android.net.wifi.SoftApConfiguration build();
+    method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBssid(@Nullable android.net.MacAddress);
+    method @NonNull public android.net.wifi.SoftApConfiguration.Builder setSsid(@Nullable String);
+    method @NonNull public android.net.wifi.SoftApConfiguration.Builder setWpa2Passphrase(@Nullable String);
+  }
+
+  public final class WifiClient implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.net.MacAddress getMacAddress();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiClient> CREATOR;
+  }
+
   @Deprecated public class WifiConfiguration implements android.os.Parcelable {
     method @Deprecated public boolean hasNoInternetAccess();
     method @Deprecated public boolean isEphemeral();
     method @Deprecated public boolean isNoInternetAccessExpected();
+    field @Deprecated public boolean allowAutojoin;
+    field @Deprecated public int carrierId;
     field @Deprecated public String creatorName;
     field @Deprecated public int creatorUid;
     field @Deprecated public String lastUpdateName;
@@ -4759,6 +4790,7 @@
 
   public class WifiManager {
     method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
+    method @RequiresPermission("android.permission.NETWORK_SETTINGS") public void allowAutojoin(int, boolean);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void connect(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void connect(int, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @Deprecated @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void disable(int, @Nullable android.net.wifi.WifiManager.ActionListener);
@@ -4779,6 +4811,7 @@
     method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsConfiguratorInitiator(@NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsEnrolleeInitiator(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
+    method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startLocalOnlyHotspot(@NonNull android.net.wifi.SoftApConfiguration, @Nullable java.util.concurrent.Executor, @Nullable android.net.wifi.WifiManager.LocalOnlyHotspotCallback);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public boolean startScan(android.os.WorkSource);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_STACK", android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean startSoftAp(@Nullable android.net.wifi.WifiConfiguration);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startSubscriptionProvisioning(@NonNull android.net.wifi.hotspot2.OsuProvider, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.hotspot2.ProvisioningCallback);
@@ -4842,9 +4875,14 @@
     field public int numUsage;
   }
 
+  public static final class WifiNetworkSuggestion.Builder {
+    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING) public android.net.wifi.WifiNetworkSuggestion.Builder setCarrierId(int);
+  }
+
   public class WifiScanner {
     method @Deprecated public void configureWifiChange(int, int, int, int, int, android.net.wifi.WifiScanner.BssidInfo[]);
     method @Deprecated public void configureWifiChange(android.net.wifi.WifiScanner.WifiChangeSettings);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public java.util.List<java.lang.Integer> getAvailableChannels(int);
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean getScanResults();
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener, android.os.WorkSource);
@@ -5202,6 +5240,23 @@
     method @NonNull public android.os.BatterySaverPolicyConfig.Builder setLocationMode(int);
   }
 
+  public class BatteryStatsManager {
+    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.os.connectivity.WifiBatteryStats getWifiBatteryStats();
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteFullWifiLockAcquiredFromSource(@NonNull android.os.WorkSource);
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteFullWifiLockReleasedFromSource(@NonNull android.os.WorkSource);
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiBatchedScanStartedFromSource(@NonNull android.os.WorkSource, @IntRange(from=0) int);
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiBatchedScanStoppedFromSource(@NonNull android.os.WorkSource);
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiMulticastDisabled(int);
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiMulticastEnabled(int);
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiOff();
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiOn();
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiRssiChanged(@IntRange(from=0xffffff81, to=0) int);
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiScanStartedFromSource(@NonNull android.os.WorkSource);
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiScanStoppedFromSource(@NonNull android.os.WorkSource);
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiState(int, @Nullable String);
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void noteWifiSupplicantStateChanged(int, boolean);
+  }
+
   public class Binder implements android.os.IBinder {
     method public static void setProxyTransactListener(@Nullable android.os.Binder.ProxyTransactListener);
   }
@@ -5406,8 +5461,8 @@
     method @RequiresPermission("android.permission.REQUEST_INCIDENT_REPORT_APPROVAL") public void cancelAuthorization(android.os.IncidentManager.AuthListener);
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void deleteIncidentReports(android.net.Uri);
     method @RequiresPermission(android.Manifest.permission.APPROVE_INCIDENT_REPORTS) public void denyReport(android.net.Uri);
-    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) @Nullable public android.os.IncidentManager.IncidentReport getIncidentReport(android.net.Uri);
-    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) @NonNull public java.util.List<android.net.Uri> getIncidentReportList(String);
+    method @Nullable @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public android.os.IncidentManager.IncidentReport getIncidentReport(android.net.Uri);
+    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public java.util.List<android.net.Uri> getIncidentReportList(String);
     method @RequiresPermission(android.Manifest.permission.APPROVE_INCIDENT_REPORTS) public java.util.List<android.os.IncidentManager.PendingReport> getPendingReports();
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void reportIncident(android.os.IncidentReportArgs);
     method @RequiresPermission("android.permission.REQUEST_INCIDENT_REPORT_APPROVAL") public void requestAuthorization(int, String, int, android.os.IncidentManager.AuthListener);
@@ -5638,6 +5693,7 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(String, android.os.UserHandle);
     method @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public int getUserSwitchability();
     method public boolean hasRestrictedProfiles();
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean hasUserRestrictionForUser(@NonNull String, @NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isAdminUser();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isGuestUser();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedProfile();
@@ -5645,6 +5701,8 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isPrimaryUser();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isRestrictedProfile();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isRestrictedProfile(@NonNull android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isSameProfileGroup(@NonNull android.os.UserHandle, @NonNull android.os.UserHandle);
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public boolean isUserUnlockingOrUnlocked(@NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean removeUser(@NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserIcon(@NonNull android.graphics.Bitmap);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserName(@Nullable String);
@@ -5688,6 +5746,30 @@
 
 }
 
+package android.os.connectivity {
+
+  public final class WifiBatteryStats implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getEnergyConsumedMaMillis();
+    method public long getIdleTimeMillis();
+    method public long getKernelActiveTimeMillis();
+    method public long getLoggingDurationMillis();
+    method public long getMonitoredRailChargeConsumedMaMillis();
+    method public long getNumAppScanRequest();
+    method public long getNumBytesRx();
+    method public long getNumBytesTx();
+    method public long getNumPacketsRx();
+    method public long getNumPacketsTx();
+    method public long getRxTimeMillis();
+    method public long getScanTimeMillis();
+    method public long getSleepTimeMillis();
+    method public long getTxTimeMillis();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.os.connectivity.WifiBatteryStats> CREATOR;
+  }
+
+}
+
 package android.os.image {
 
   public class DynamicSystemClient {
@@ -5931,7 +6013,7 @@
     field public static final String NAMESPACE_AUTOFILL = "autofill";
     field public static final String NAMESPACE_CONNECTIVITY = "connectivity";
     field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
-    field public static final String NAMESPACE_DEX_BOOT = "dex_boot";
+    field @Deprecated public static final String NAMESPACE_DEX_BOOT = "dex_boot";
     field public static final String NAMESPACE_DISPLAY_MANAGER = "display_manager";
     field public static final String NAMESPACE_GAME_DRIVER = "game_driver";
     field public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
@@ -5939,6 +6021,7 @@
     field public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
     field public static final String NAMESPACE_NETD_NATIVE = "netd_native";
     field public static final String NAMESPACE_PACKAGE_MANAGER_SERVICE = "package_manager_service";
+    field public static final String NAMESPACE_PERMISSIONS = "permissions";
     field public static final String NAMESPACE_PRIVACY = "privacy";
     field public static final String NAMESPACE_ROLLBACK = "rollback";
     field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
@@ -6191,15 +6274,21 @@
     field public static final String DELIVERY_TIME = "date";
     field public static final String ETWS_WARNING_TYPE = "etws_warning_type";
     field public static final String GEOGRAPHICAL_SCOPE = "geo_scope";
+    field public static final String GEOMETRIES = "geometries";
     field public static final String LAC = "lac";
     field public static final String LANGUAGE_CODE = "language";
+    field public static final String MAXIMUM_WAIT_TIME = "maximum_wait_time";
     field public static final String MESSAGE_BODY = "body";
+    field public static final String MESSAGE_BROADCASTED = "message_broadcasted";
     field public static final String MESSAGE_FORMAT = "format";
+    field @NonNull @RequiresPermission(android.Manifest.permission.READ_CELL_BROADCASTS) public static final android.net.Uri MESSAGE_HISTORY_URI;
     field public static final String MESSAGE_PRIORITY = "priority";
     field public static final String MESSAGE_READ = "read";
     field public static final String PLMN = "plmn";
+    field public static final String RECEIVED_TIME = "received_time";
     field public static final String SERIAL_NUMBER = "serial_number";
     field public static final String SERVICE_CATEGORY = "service_category";
+    field public static final String SLOT_INDEX = "slot_index";
   }
 
   public final class TimeZoneRulesDataContract {
@@ -6223,7 +6312,7 @@
 package android.security.keystore {
 
   public abstract class AttestationUtils {
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @NonNull public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, @NonNull int[], @NonNull byte[]) throws android.security.keystore.DeviceIdAttestationException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, @NonNull int[], @NonNull byte[]) throws android.security.keystore.DeviceIdAttestationException;
     field public static final int ID_TYPE_IMEI = 2; // 0x2
     field public static final int ID_TYPE_MEID = 3; // 0x3
     field public static final int ID_TYPE_SERIAL = 1; // 0x1
@@ -6304,18 +6393,18 @@
   }
 
   public class RecoveryController {
-    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public android.security.keystore.recovery.RecoverySession createRecoverySession();
+    method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public android.security.keystore.recovery.RecoverySession createRecoverySession();
     method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.security.Key generateKey(@NonNull String) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
-    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public java.security.Key generateKey(@NonNull String, @Nullable byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
-    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public java.util.List<java.lang.String> getAliases() throws android.security.keystore.recovery.InternalRecoveryServiceException;
-    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public static android.security.keystore.recovery.RecoveryController getInstance(@NonNull android.content.Context);
-    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @Nullable public java.security.Key getKey(@NonNull String) throws android.security.keystore.recovery.InternalRecoveryServiceException, java.security.UnrecoverableKeyException;
-    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @Nullable public android.security.keystore.recovery.KeyChainSnapshot getKeyChainSnapshot() throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.security.Key generateKey(@NonNull String, @Nullable byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.util.List<java.lang.String> getAliases() throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public static android.security.keystore.recovery.RecoveryController getInstance(@NonNull android.content.Context);
+    method @Nullable @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.security.Key getKey(@NonNull String) throws android.security.keystore.recovery.InternalRecoveryServiceException, java.security.UnrecoverableKeyException;
+    method @Nullable @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public android.security.keystore.recovery.KeyChainSnapshot getKeyChainSnapshot() throws android.security.keystore.recovery.InternalRecoveryServiceException;
     method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public int[] getRecoverySecretTypes() throws android.security.keystore.recovery.InternalRecoveryServiceException;
     method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public int getRecoveryStatus(@NonNull String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
-    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public java.util.Map<java.lang.String,java.security.cert.X509Certificate> getRootCertificates();
+    method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.util.Map<java.lang.String,java.security.cert.X509Certificate> getRootCertificates();
     method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.security.Key importKey(@NonNull String, @NonNull byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
-    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public java.security.Key importKey(@NonNull String, @NonNull byte[], @Nullable byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.security.Key importKey(@NonNull String, @NonNull byte[], @Nullable byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
     method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void initRecoveryService(@NonNull String, @NonNull byte[], @NonNull byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
     method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public static boolean isRecoverableKeyStoreEnabled(@NonNull android.content.Context);
     method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void removeKey(@NonNull String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
@@ -6330,8 +6419,8 @@
 
   public class RecoverySession implements java.lang.AutoCloseable {
     method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void close();
-    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public java.util.Map<java.lang.String,java.security.Key> recoverKeyChainSnapshot(@NonNull byte[], @NonNull java.util.List<android.security.keystore.recovery.WrappedApplicationKey>) throws android.security.keystore.recovery.DecryptionFailedException, android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.SessionExpiredException;
-    method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @NonNull public byte[] start(@NonNull String, @NonNull java.security.cert.CertPath, @NonNull byte[], @NonNull byte[], @NonNull java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.util.Map<java.lang.String,java.security.Key> recoverKeyChainSnapshot(@NonNull byte[], @NonNull java.util.List<android.security.keystore.recovery.WrappedApplicationKey>) throws android.security.keystore.recovery.DecryptionFailedException, android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.SessionExpiredException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public byte[] start(@NonNull String, @NonNull java.security.cert.CertPath, @NonNull byte[], @NonNull byte[], @NonNull java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
   }
 
   public class SessionExpiredException extends java.security.GeneralSecurityException {
@@ -6474,7 +6563,29 @@
   public abstract class ApnService extends android.app.Service {
     ctor public ApnService();
     method @NonNull public android.os.IBinder onBind(@Nullable android.content.Intent);
-    method @WorkerThread @NonNull public abstract java.util.List<android.content.ContentValues> onRestoreApns(int);
+    method @NonNull @WorkerThread public abstract java.util.List<android.content.ContentValues> onRestoreApns(int);
+  }
+
+  public abstract class CarrierMessagingServiceWrapper {
+    ctor public CarrierMessagingServiceWrapper();
+    method public boolean bindToCarrierMessagingService(@NonNull android.content.Context, @NonNull String);
+    method public void disposeConnection(@NonNull android.content.Context);
+    method public void downloadMms(@NonNull android.net.Uri, int, @NonNull android.net.Uri, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper);
+    method public void filterSms(@NonNull android.service.carrier.MessagePdu, @NonNull String, int, int, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper);
+    method public abstract void onServiceReady();
+    method public void sendDataSms(@NonNull byte[], int, @NonNull String, int, int, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper);
+    method public void sendMms(@NonNull android.net.Uri, int, @NonNull android.net.Uri, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper);
+    method public void sendMultipartTextSms(@NonNull java.util.List<java.lang.String>, int, @NonNull String, int, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper);
+    method public void sendTextSms(@NonNull String, int, @NonNull String, int, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper);
+  }
+
+  public abstract static class CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper {
+    ctor public CarrierMessagingServiceWrapper.CarrierMessagingCallbackWrapper();
+    method public void onDownloadMmsComplete(int);
+    method public void onFilterComplete(int);
+    method public void onSendMmsComplete(int, @Nullable byte[]);
+    method public void onSendMultipartSmsComplete(int, @Nullable int[]);
+    method public void onSendSmsComplete(int, int);
   }
 
 }
@@ -6586,13 +6697,13 @@
     method public android.service.euicc.EuiccProfileInfo.Builder setUiccAccessRule(@Nullable java.util.List<android.telephony.UiccAccessRule>);
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(flag=true, prefix={"POLICY_RULE_"}, value={android.service.euicc.EuiccProfileInfo.POLICY_RULE_DO_NOT_DISABLE, android.service.euicc.EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE, android.service.euicc.EuiccProfileInfo.POLICY_RULE_DELETE_AFTER_DISABLING}) public static @interface EuiccProfileInfo.PolicyRule {
+  @IntDef(flag=true, prefix={"POLICY_RULE_"}, value={android.service.euicc.EuiccProfileInfo.POLICY_RULE_DO_NOT_DISABLE, android.service.euicc.EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE, android.service.euicc.EuiccProfileInfo.POLICY_RULE_DELETE_AFTER_DISABLING}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccProfileInfo.PolicyRule {
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(prefix={"PROFILE_CLASS_"}, value={android.service.euicc.EuiccProfileInfo.PROFILE_CLASS_TESTING, android.service.euicc.EuiccProfileInfo.PROFILE_CLASS_PROVISIONING, android.service.euicc.EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL, 0xffffffff}) public static @interface EuiccProfileInfo.ProfileClass {
+  @IntDef(prefix={"PROFILE_CLASS_"}, value={android.service.euicc.EuiccProfileInfo.PROFILE_CLASS_TESTING, android.service.euicc.EuiccProfileInfo.PROFILE_CLASS_PROVISIONING, android.service.euicc.EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL, 0xffffffff}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccProfileInfo.ProfileClass {
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(prefix={"PROFILE_STATE_"}, value={android.service.euicc.EuiccProfileInfo.PROFILE_STATE_DISABLED, android.service.euicc.EuiccProfileInfo.PROFILE_STATE_ENABLED, 0xffffffff}) public static @interface EuiccProfileInfo.ProfileState {
+  @IntDef(prefix={"PROFILE_STATE_"}, value={android.service.euicc.EuiccProfileInfo.PROFILE_STATE_DISABLED, android.service.euicc.EuiccProfileInfo.PROFILE_STATE_ENABLED, 0xffffffff}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccProfileInfo.ProfileState {
   }
 
   public abstract class EuiccService extends android.app.Service {
@@ -6771,7 +6882,7 @@
 package android.service.oemlock {
 
   public class OemLockManager {
-    method @RequiresPermission(android.Manifest.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE) @Nullable public String getLockName();
+    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE) public String getLockName();
     method @RequiresPermission(android.Manifest.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE) public boolean isOemUnlockAllowedByCarrier();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USER_OEM_UNLOCK_STATE) public boolean isOemUnlockAllowedByUser();
     method @RequiresPermission(android.Manifest.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE) public void setOemUnlockAllowedByCarrier(boolean, @Nullable byte[]);
@@ -6784,7 +6895,7 @@
 
   public class PersistentDataBlockManager {
     method @RequiresPermission("android.permission.ACCESS_PDB_STATE") public int getDataBlockSize();
-    method @RequiresPermission(anyOf={android.Manifest.permission.READ_OEM_UNLOCK_STATE, "android.permission.OEM_UNLOCK_STATE"}) @android.service.persistentdata.PersistentDataBlockManager.FlashLockState public int getFlashLockState();
+    method @android.service.persistentdata.PersistentDataBlockManager.FlashLockState @RequiresPermission(anyOf={android.Manifest.permission.READ_OEM_UNLOCK_STATE, "android.permission.OEM_UNLOCK_STATE"}) public int getFlashLockState();
     method public long getMaximumDataBlockSize();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_OEM_UNLOCK_STATE, "android.permission.OEM_UNLOCK_STATE"}) public boolean getOemUnlockEnabled();
     method public byte[] read();
@@ -6907,9 +7018,11 @@
     method @Deprecated public final android.view.textclassifier.TextClassifier getLocalTextClassifier();
     method @Nullable public final android.os.IBinder onBind(android.content.Intent);
     method @MainThread public abstract void onClassifyText(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextClassification.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextClassification>);
+    method public void onConnected();
     method @MainThread public void onCreateTextClassificationSession(@NonNull android.view.textclassifier.TextClassificationContext, @NonNull android.view.textclassifier.TextClassificationSessionId);
     method @MainThread public void onDestroyTextClassificationSession(@NonNull android.view.textclassifier.TextClassificationSessionId);
     method @MainThread public void onDetectLanguage(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextLanguage.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextLanguage>);
+    method public void onDisconnected();
     method @MainThread public abstract void onGenerateLinks(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextLinks.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextLinks>);
     method @Deprecated @MainThread public void onSelectionEvent(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.SelectionEvent);
     method @MainThread public void onSuggestConversationActions(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.ConversationActions.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.ConversationActions>);
@@ -7372,9 +7485,10 @@
 
   public abstract class CellBroadcastService extends android.app.Service {
     ctor public CellBroadcastService();
-    method @CallSuper public android.os.IBinder onBind(android.content.Intent);
-    method public abstract void onCdmaCellBroadcastSms(int, byte[], int);
-    method public abstract void onGsmCellBroadcastSms(int, byte[]);
+    method @CallSuper public android.os.IBinder onBind(@Nullable android.content.Intent);
+    method public abstract void onCdmaCellBroadcastSms(int, @NonNull byte[], int);
+    method public abstract void onCdmaScpMessage(int, @NonNull java.util.List<android.telephony.cdma.CdmaSmsCbProgramData>, @NonNull String, @NonNull java.util.function.Consumer<android.os.Bundle>);
+    method public abstract void onGsmCellBroadcastSms(int, @NonNull byte[]);
     field public static final String CELL_BROADCAST_SERVICE_INTERFACE = "android.telephony.CellBroadcastService";
   }
 
@@ -7805,6 +7919,14 @@
     field public static final int WIFI_LOST = 59; // 0x3b
   }
 
+  public final class ImsiEncryptionInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public String getKeyIdentifier();
+    method @Nullable public java.security.PublicKey getPublicKey();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ImsiEncryptionInfo> CREATOR;
+  }
+
   public final class LteVopsSupportInfo implements android.os.Parcelable {
     ctor public LteVopsSupportInfo(int, int);
     method public int describeContents();
@@ -8217,24 +8339,6 @@
     method public boolean disableCellBroadcastRange(int, int, int);
     method public boolean enableCellBroadcastRange(int, int, int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void sendMultipartTextMessageWithoutPersisting(String, String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>);
-    field public static final int RESULT_CANCELLED = 23; // 0x17
-    field public static final int RESULT_ENCODING_ERROR = 18; // 0x12
-    field public static final int RESULT_ERROR_FDN_CHECK_FAILURE = 6; // 0x6
-    field public static final int RESULT_ERROR_NONE = 0; // 0x0
-    field public static final int RESULT_INTERNAL_ERROR = 21; // 0x15
-    field public static final int RESULT_INVALID_ARGUMENTS = 11; // 0xb
-    field public static final int RESULT_INVALID_SMSC_ADDRESS = 19; // 0x13
-    field public static final int RESULT_INVALID_SMS_FORMAT = 14; // 0xe
-    field public static final int RESULT_INVALID_STATE = 12; // 0xc
-    field public static final int RESULT_MODEM_ERROR = 16; // 0x10
-    field public static final int RESULT_NETWORK_ERROR = 17; // 0x11
-    field public static final int RESULT_NETWORK_REJECT = 10; // 0xa
-    field public static final int RESULT_NO_MEMORY = 13; // 0xd
-    field public static final int RESULT_NO_RESOURCES = 22; // 0x16
-    field public static final int RESULT_OPERATION_NOT_ALLOWED = 20; // 0x14
-    field public static final int RESULT_RADIO_NOT_AVAILABLE = 9; // 0x9
-    field public static final int RESULT_REQUEST_NOT_SUPPORTED = 24; // 0x18
-    field public static final int RESULT_SYSTEM_ERROR = 15; // 0xf
   }
 
   public class SubscriptionInfo implements android.os.Parcelable {
@@ -8294,6 +8398,9 @@
 
   public class TelephonyManager {
     method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void carrierActionReportDefaultNetworkStatus(int, boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void carrierActionResetAll(int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void carrierActionSetRadioEnabled(int, boolean);
     method public int checkCarrierPrivilegesForPackage(String);
     method public int checkCarrierPrivilegesForPackageAnyPhone(String);
     method public void dial(String);
@@ -8301,8 +8408,10 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean enableDataConnectivity();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean enableModemForSlot(int, boolean);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void enableVideoCalling(boolean);
+    method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void factoryReset(int);
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getAidForAppType(int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);
+    method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules();
@@ -8356,6 +8465,7 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
     method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig();
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean);
@@ -8379,6 +8489,7 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void toggleRadioOnOff();
     method public void updateServiceLocation();
     field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_ANOMALY_REPORTED = "android.telephony.action.ANOMALY_REPORTED";
+    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_OTA_EMERGENCY_NUMBER_DB_INSTALLED = "android.telephony.action.OTA_EMERGENCY_NUMBER_DB_INSTALLED";
     field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED";
     field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED";
     field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED";
@@ -8391,6 +8502,8 @@
     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";
     field public static final String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING";
+    field public static final int KEY_TYPE_EPDG = 1; // 0x1
+    field public static final int KEY_TYPE_WLAN = 2; // 0x2
     field public static final long NETWORK_TYPE_BITMASK_1xRTT = 64L; // 0x40L
     field public static final long NETWORK_TYPE_BITMASK_CDMA = 8L; // 0x8L
     field public static final long NETWORK_TYPE_BITMASK_EDGE = 2L; // 0x2L
@@ -8682,10 +8795,10 @@
     field public static final int RESULT_UNKNOWN_ERROR = -1; // 0xffffffff
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(prefix={"CANCEL_REASON_"}, value={android.telephony.euicc.EuiccCardManager.CANCEL_REASON_END_USER_REJECTED, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_POSTPONED, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_TIMEOUT, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_PPR_NOT_ALLOWED}) public static @interface EuiccCardManager.CancelReason {
+  @IntDef(prefix={"CANCEL_REASON_"}, value={android.telephony.euicc.EuiccCardManager.CANCEL_REASON_END_USER_REJECTED, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_POSTPONED, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_TIMEOUT, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_PPR_NOT_ALLOWED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccCardManager.CancelReason {
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(flag=true, prefix={"RESET_OPTION_"}, value={android.telephony.euicc.EuiccCardManager.RESET_OPTION_DELETE_OPERATIONAL_PROFILES, android.telephony.euicc.EuiccCardManager.RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES, android.telephony.euicc.EuiccCardManager.RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS}) public static @interface EuiccCardManager.ResetOption {
+  @IntDef(flag=true, prefix={"RESET_OPTION_"}, value={android.telephony.euicc.EuiccCardManager.RESET_OPTION_DELETE_OPERATIONAL_PROFILES, android.telephony.euicc.EuiccCardManager.RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES, android.telephony.euicc.EuiccCardManager.RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccCardManager.ResetOption {
   }
 
   public static interface EuiccCardManager.ResultCallback<T> {
@@ -8741,7 +8854,7 @@
     field public static final int EVENT_INSTALL = 1; // 0x1
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(flag=true, prefix={"EVENT_"}, value={android.telephony.euicc.EuiccNotification.EVENT_INSTALL, android.telephony.euicc.EuiccNotification.EVENT_ENABLE, android.telephony.euicc.EuiccNotification.EVENT_DISABLE, android.telephony.euicc.EuiccNotification.EVENT_DELETE}) public static @interface EuiccNotification.Event {
+  @IntDef(flag=true, prefix={"EVENT_"}, value={android.telephony.euicc.EuiccNotification.EVENT_INSTALL, android.telephony.euicc.EuiccNotification.EVENT_ENABLE, android.telephony.euicc.EuiccNotification.EVENT_DISABLE, android.telephony.euicc.EuiccNotification.EVENT_DELETE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccNotification.Event {
   }
 
   public final class EuiccRulesAuthTable implements android.os.Parcelable {
@@ -8759,7 +8872,7 @@
     method public android.telephony.euicc.EuiccRulesAuthTable build();
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(flag=true, prefix={"POLICY_RULE_FLAG_"}, value={android.telephony.euicc.EuiccRulesAuthTable.POLICY_RULE_FLAG_CONSENT_REQUIRED}) public static @interface EuiccRulesAuthTable.PolicyRuleFlag {
+  @IntDef(flag=true, prefix={"POLICY_RULE_FLAG_"}, value={android.telephony.euicc.EuiccRulesAuthTable.POLICY_RULE_FLAG_CONSENT_REQUIRED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccRulesAuthTable.PolicyRuleFlag {
   }
 
 }
@@ -8968,17 +9081,23 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsExternalCallState> CREATOR;
   }
 
-  public class ImsMmTelManager {
+  public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
     method @NonNull public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiModeSetting();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiRoamingModeSetting();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAdvancedCallingSettingEnabled();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAvailable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void isSupported(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, @NonNull java.util.function.Consumer<java.lang.Boolean>, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isTtyOverVolteEnabled();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVoWiFiRoamingSettingEnabled();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVoWiFiSettingEnabled();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVtSettingEnabled();
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException;
+    method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerMmTelCapabilityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAdvancedCallingSettingEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean);
@@ -8988,7 +9107,8 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiRoamingSettingEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiSettingEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVtSettingEnabled(boolean);
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterMmTelCapabilityCallback(@NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback);
     field public static final int WIFI_MODE_CELLULAR_PREFERRED = 1; // 0x1
     field public static final int WIFI_MODE_WIFI_ONLY = 0; // 0x0
@@ -9000,12 +9120,8 @@
     method public void onCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.MmTelFeature.MmTelCapabilities);
   }
 
-  public static class ImsMmTelManager.RegistrationCallback {
-    ctor public ImsMmTelManager.RegistrationCallback();
-    method public void onRegistered(int);
-    method public void onRegistering(int);
-    method public void onTechnologyChangeFailed(int, @Nullable android.telephony.ims.ImsReasonInfo);
-    method public void onUnregistered(@Nullable android.telephony.ims.ImsReasonInfo);
+  @Deprecated public static class ImsMmTelManager.RegistrationCallback extends android.telephony.ims.RegistrationManager.RegistrationCallback {
+    ctor @Deprecated public ImsMmTelManager.RegistrationCallback();
   }
 
   public final class ImsReasonInfo implements android.os.Parcelable {
@@ -9381,14 +9497,17 @@
   }
 
   public class ImsUtListener {
+    method public void onLineIdentificationSupplementaryServiceResponse(int, @NonNull android.telephony.ims.ImsSsInfo);
     method public void onSupplementaryServiceIndication(android.telephony.ims.ImsSsData);
     method public void onUtConfigurationCallBarringQueried(int, android.telephony.ims.ImsSsInfo[]);
     method public void onUtConfigurationCallForwardQueried(int, android.telephony.ims.ImsCallForwardInfo[]);
     method public void onUtConfigurationCallWaitingQueried(int, android.telephony.ims.ImsSsInfo[]);
-    method public void onUtConfigurationQueried(int, android.os.Bundle);
+    method @Deprecated public void onUtConfigurationQueried(int, android.os.Bundle);
     method public void onUtConfigurationQueryFailed(int, android.telephony.ims.ImsReasonInfo);
     method public void onUtConfigurationUpdateFailed(int, android.telephony.ims.ImsReasonInfo);
     method public void onUtConfigurationUpdated(int);
+    field @Deprecated public static final String BUNDLE_KEY_CLIR = "queryClir";
+    field @Deprecated public static final String BUNDLE_KEY_SSINFO = "imsSsInfo";
   }
 
   public abstract class ImsVideoCallProvider {
@@ -9415,12 +9534,12 @@
 
   public class ProvisioningManager {
     method @NonNull public static android.telephony.ims.ProvisioningManager createForSubscriptionId(int);
-    method @WorkerThread @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getProvisioningIntValue(int);
-    method @WorkerThread @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public int getProvisioningIntValue(int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public String getProvisioningStringValue(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int);
-    method @WorkerThread @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback);
     field public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; // 0x1b
@@ -9437,6 +9556,24 @@
     method public void onProvisioningStringChanged(int, @NonNull String);
   }
 
+  public interface RegistrationManager {
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
+    field public static final int REGISTRATION_STATE_NOT_REGISTERED = 0; // 0x0
+    field public static final int REGISTRATION_STATE_REGISTERED = 2; // 0x2
+    field public static final int REGISTRATION_STATE_REGISTERING = 1; // 0x1
+  }
+
+  public static class RegistrationManager.RegistrationCallback {
+    ctor public RegistrationManager.RegistrationCallback();
+    method public void onRegistered(int);
+    method public void onRegistering(int);
+    method public void onTechnologyChangeFailed(int, @Nullable android.telephony.ims.ImsReasonInfo);
+    method public void onUnregistered(@Nullable android.telephony.ims.ImsReasonInfo);
+  }
+
 }
 
 package android.telephony.ims.feature {
@@ -9501,6 +9638,8 @@
     method public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus();
     method public void setUiTtyMode(int, @Nullable android.os.Message);
     method @android.telephony.ims.feature.MmTelFeature.ProcessCallResult public int shouldProcessCall(@NonNull String[]);
+    field public static final String EXTRA_IS_UNKNOWN_CALL = "android.telephony.ims.feature.extra.IS_UNKNOWN_CALL";
+    field public static final String EXTRA_IS_USSD = "android.telephony.ims.feature.extra.IS_USSD";
     field public static final int PROCESS_CALL_CSFB = 1; // 0x1
     field public static final int PROCESS_CALL_IMS = 0; // 0x0
   }
diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt
index 57a853a..21526d0 100644
--- a/api/system-lint-baseline.txt
+++ b/api/system-lint-baseline.txt
@@ -135,6 +135,12 @@
     
 
 
+MutableBareField: android.net.wifi.WifiConfiguration#allowAutojoin:
+    
+MutableBareField: android.net.wifi.WifiConfiguration#carrierId:
+    
+
+
 NoClone: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
     
 
@@ -257,6 +263,8 @@
     
 SamShouldBeLast: android.net.ConnectivityManager#createSocketKeepalive(android.net.Network, android.net.IpSecManager.UdpEncapsulationSocket, java.net.InetAddress, java.net.InetAddress, java.util.concurrent.Executor, android.net.SocketKeepalive.Callback):
     
+SamShouldBeLast: android.net.wifi.WifiManager#startLocalOnlyHotspot(android.net.wifi.SoftApConfiguration, java.util.concurrent.Executor, android.net.wifi.WifiManager.LocalOnlyHotspotCallback):
+    
 SamShouldBeLast: android.net.wifi.rtt.WifiRttManager#startRanging(android.net.wifi.rtt.RangingRequest, java.util.concurrent.Executor, android.net.wifi.rtt.RangingResultCallback):
     
 SamShouldBeLast: android.nfc.NfcAdapter#enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle):
diff --git a/api/test-current.txt b/api/test-current.txt
index b3834bf..495e57a 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -71,6 +71,9 @@
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
     method public static void resumeAppSwitches() throws android.os.RemoteException;
     method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int);
+    field public static final int PROCESS_CAPABILITY_ALL = 1; // 0x1
+    field public static final int PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1; // 0x1
+    field public static final int PROCESS_CAPABILITY_NONE = 0; // 0x0
   }
 
   public static interface ActivityManager.OnUidImportanceListener {
@@ -233,7 +236,7 @@
     field public static final int UID_STATE_CACHED = 700; // 0x2bc
     field public static final int UID_STATE_FOREGROUND = 500; // 0x1f4
     field public static final int UID_STATE_FOREGROUND_SERVICE = 400; // 0x190
-    field public static final int UID_STATE_FOREGROUND_SERVICE_LOCATION = 300; // 0x12c
+    field @Deprecated public static final int UID_STATE_FOREGROUND_SERVICE_LOCATION = 300; // 0x12c
     field public static final int UID_STATE_PERSISTENT = 100; // 0x64
     field public static final int UID_STATE_TOP = 200; // 0xc8
   }
@@ -852,8 +855,8 @@
     method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void blockRollbackManager(long);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
     method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
-    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
-    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
     method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void reloadPersistedData();
     field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS";
     field public static final String EXTRA_STATUS_MESSAGE = "android.content.rollback.extra.STATUS_MESSAGE";
@@ -1136,17 +1139,20 @@
   public final class LocationRequest implements android.os.Parcelable {
     method @NonNull public static android.location.LocationRequest create();
     method public int describeContents();
-    method public long getExpireAt();
+    method @Deprecated public long getExpireAt();
+    method public long getExpireIn();
     method public long getFastestInterval();
     method public long getInterval();
     method public int getNumUpdates();
     method public int getQuality();
     method public boolean isLocationSettingsIgnored();
-    method @NonNull public android.location.LocationRequest setExpireAt(long);
+    method public boolean isLowPowerMode();
+    method @Deprecated @NonNull public android.location.LocationRequest setExpireAt(long);
     method @NonNull public android.location.LocationRequest setExpireIn(long);
     method @NonNull public android.location.LocationRequest setFastestInterval(long);
     method @NonNull public android.location.LocationRequest setInterval(long);
-    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @NonNull public android.location.LocationRequest setLocationSettingsIgnored(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
+    method @NonNull public android.location.LocationRequest setLowPowerMode(boolean);
     method @NonNull public android.location.LocationRequest setNumUpdates(int);
     method @NonNull public android.location.LocationRequest setProvider(@NonNull String);
     method @NonNull public android.location.LocationRequest setQuality(int);
@@ -1722,7 +1728,8 @@
     method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException;
     method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
     method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int);
-    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
+    method @Deprecated @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
+    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int, @NonNull byte[]);
   }
 
 }
@@ -1920,8 +1927,8 @@
     method @RequiresPermission("android.permission.REQUEST_INCIDENT_REPORT_APPROVAL") public void cancelAuthorization(android.os.IncidentManager.AuthListener);
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void deleteIncidentReports(android.net.Uri);
     method @RequiresPermission(android.Manifest.permission.APPROVE_INCIDENT_REPORTS) public void denyReport(android.net.Uri);
-    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) @Nullable public android.os.IncidentManager.IncidentReport getIncidentReport(android.net.Uri);
-    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) @NonNull public java.util.List<android.net.Uri> getIncidentReportList(String);
+    method @Nullable @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public android.os.IncidentManager.IncidentReport getIncidentReport(android.net.Uri);
+    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public java.util.List<android.net.Uri> getIncidentReportList(String);
     method @RequiresPermission(android.Manifest.permission.APPROVE_INCIDENT_REPORTS) public java.util.List<android.os.IncidentManager.PendingReport> getPendingReports();
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void reportIncident(android.os.IncidentReportArgs);
     method @RequiresPermission("android.permission.REQUEST_INCIDENT_REPORT_APPROVAL") public void requestAuthorization(int, String, int, android.os.IncidentManager.AuthListener);
@@ -2063,6 +2070,8 @@
     method @NonNull public static String get(@NonNull String);
     method @NonNull public static String get(@NonNull String, @Nullable String);
     method public static boolean getBoolean(@NonNull String, boolean);
+    method public static int getInt(@NonNull String, int);
+    method public static long getLong(@NonNull String, long);
   }
 
   public final class UserHandle implements android.os.Parcelable {
@@ -2373,6 +2382,7 @@
     method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean);
     field public static final String NAMESPACE_AUTOFILL = "autofill";
     field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
+    field public static final String NAMESPACE_PERMISSIONS = "permissions";
     field public static final String NAMESPACE_PRIVACY = "privacy";
     field public static final String NAMESPACE_ROLLBACK = "rollback";
     field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
@@ -2416,6 +2426,7 @@
   }
 
   public static final class Settings.Global extends android.provider.Settings.NameValueTable {
+    field public static final String APP_OPS_CONSTANTS = "app_ops_constants";
     field public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
     field public static final String AUTOMATIC_POWER_SAVE_MODE = "automatic_power_save_mode";
     field public static final String BATTERY_SAVER_CONSTANTS = "battery_saver_constants";
@@ -2455,6 +2466,36 @@
     field public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
   }
 
+  public static final class Telephony.CellBroadcasts implements android.provider.BaseColumns {
+    field public static final String CID = "cid";
+    field public static final String CMAS_CATEGORY = "cmas_category";
+    field public static final String CMAS_CERTAINTY = "cmas_certainty";
+    field public static final String CMAS_MESSAGE_CLASS = "cmas_message_class";
+    field public static final String CMAS_RESPONSE_TYPE = "cmas_response_type";
+    field public static final String CMAS_SEVERITY = "cmas_severity";
+    field public static final String CMAS_URGENCY = "cmas_urgency";
+    field @NonNull public static final android.net.Uri CONTENT_URI;
+    field public static final String DEFAULT_SORT_ORDER = "date DESC";
+    field public static final String DELIVERY_TIME = "date";
+    field public static final String ETWS_WARNING_TYPE = "etws_warning_type";
+    field public static final String GEOGRAPHICAL_SCOPE = "geo_scope";
+    field public static final String GEOMETRIES = "geometries";
+    field public static final String LAC = "lac";
+    field public static final String LANGUAGE_CODE = "language";
+    field public static final String MAXIMUM_WAIT_TIME = "maximum_wait_time";
+    field public static final String MESSAGE_BODY = "body";
+    field public static final String MESSAGE_BROADCASTED = "message_broadcasted";
+    field public static final String MESSAGE_FORMAT = "format";
+    field @NonNull @RequiresPermission(android.Manifest.permission.READ_CELL_BROADCASTS) public static final android.net.Uri MESSAGE_HISTORY_URI;
+    field public static final String MESSAGE_PRIORITY = "priority";
+    field public static final String MESSAGE_READ = "read";
+    field public static final String PLMN = "plmn";
+    field public static final String RECEIVED_TIME = "received_time";
+    field public static final String SERIAL_NUMBER = "serial_number";
+    field public static final String SERVICE_CATEGORY = "service_category";
+    field public static final String SLOT_INDEX = "slot_index";
+  }
+
   public static final class Telephony.Sms.Intents {
     field public static final String SMS_CARRIER_PROVISION_ACTION = "android.provider.Telephony.SMS_CARRIER_PROVISION";
   }
@@ -2477,7 +2518,7 @@
 package android.security.keystore {
 
   public abstract class AttestationUtils {
-    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @NonNull public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, @NonNull int[], @NonNull byte[]) throws android.security.keystore.DeviceIdAttestationException;
+    method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, @NonNull int[], @NonNull byte[]) throws android.security.keystore.DeviceIdAttestationException;
     field public static final int ID_TYPE_IMEI = 2; // 0x2
     field public static final int ID_TYPE_MEID = 3; // 0x3
     field public static final int ID_TYPE_SERIAL = 1; // 0x1
diff --git a/api/test-lint-baseline.txt b/api/test-lint-baseline.txt
new file mode 100644
index 0000000..9606413
--- /dev/null
+++ b/api/test-lint-baseline.txt
@@ -0,0 +1,2249 @@
+// Baseline format: 1.0
+AcronymName: android.app.NotificationChannel#isImportanceLockedByOEM():
+    
+AcronymName: android.app.NotificationChannel#setImportanceLockedByOEM(boolean):
+    
+
+
+ActionValue: android.location.Location#EXTRA_NO_GPS_LOCATION:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#ACTION_CLEANUP:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#ACTION_DOWNLOAD_RESULT_INTERNAL:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#ACTION_FILE_DESCRIPTOR_REQUEST:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_FD_COUNT:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_FINAL_URI:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_FREE_URI_LIST:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_PAUSED_LIST:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_PAUSED_URI_LIST:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_SERVICE_ID:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_TEMP_FILES_IN_USE:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_TEMP_FILE_ROOT:
+    
+ActionValue: android.telephony.mbms.vendor.VendorUtils#EXTRA_TEMP_LIST:
+    
+
+
+ArrayReturn: android.app.UiAutomation#executeShellCommandRw(String):
+    
+ArrayReturn: android.location.GnssMeasurementsEvent#GnssMeasurementsEvent(android.location.GnssClock, android.location.GnssMeasurement[]) parameter #1:
+    
+ArrayReturn: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #10:
+    
+ArrayReturn: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #11:
+    
+ArrayReturn: android.metrics.LogMaker#LogMaker(Object[]) parameter #0:
+    
+ArrayReturn: android.metrics.LogMaker#deserialize(Object[]) parameter #0:
+    
+ArrayReturn: android.metrics.LogMaker#serialize():
+    
+ArrayReturn: android.net.TestNetworkManager#createTunInterface(android.net.LinkAddress[]) parameter #0:
+    
+ArrayReturn: android.os.HwBlob#wrapArray(boolean[]):
+    
+ArrayReturn: android.os.HwBlob#wrapArray(byte[]):
+    
+ArrayReturn: android.os.HwBlob#wrapArray(double[]):
+    
+ArrayReturn: android.os.HwBlob#wrapArray(float[]):
+    
+ArrayReturn: android.os.HwBlob#wrapArray(int[]):
+    
+ArrayReturn: android.os.HwBlob#wrapArray(long[]):
+    
+ArrayReturn: android.os.HwBlob#wrapArray(short[]):
+    
+ArrayReturn: android.os.NativeHandle#NativeHandle(java.io.FileDescriptor[], int[], boolean) parameter #0:
+    
+ArrayReturn: android.os.NativeHandle#getFileDescriptors():
+    
+ArrayReturn: android.security.keystore.AttestationUtils#attestDeviceIds(android.content.Context, int[], byte[]):
+    
+ArrayReturn: android.view.FocusFinder#sort(android.view.View[], int, int, android.view.ViewGroup, boolean) parameter #0:
+    
+ArrayReturn: android.view.contentcapture.ViewNode#getAutofillOptions():
+    
+ArrayReturn: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillOptions(CharSequence[]) parameter #0:
+    
+ArrayReturn: android.view.inspector.InspectableProperty#enumMapping():
+    
+ArrayReturn: android.view.inspector.InspectableProperty#flagMapping():
+    
+
+
+AutoBoxing: android.os.HwBlob#wrapArray(byte[]):
+    
+AutoBoxing: android.os.HwBlob#wrapArray(double[]):
+    
+AutoBoxing: android.os.HwBlob#wrapArray(float[]):
+    
+AutoBoxing: android.os.HwBlob#wrapArray(int[]):
+    
+AutoBoxing: android.os.HwBlob#wrapArray(long[]):
+    
+AutoBoxing: android.os.HwBlob#wrapArray(short[]):
+    
+AutoBoxing: android.os.VintfObject#getTargetFrameworkCompatibilityMatrixVersion():
+    
+
+
+BannedThrow: android.app.ActivityTaskManager#removeStacksInWindowingModes(int[]):
+    
+BannedThrow: android.app.ActivityTaskManager#removeStacksWithActivityTypes(int[]):
+    
+BannedThrow: android.app.ActivityTaskManager#setTaskWindowingMode(int, int, boolean):
+    
+BannedThrow: android.app.ActivityTaskManager#setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect, boolean):
+    
+BannedThrow: android.media.audiofx.AudioEffect#getParameter(byte[], byte[]):
+    
+BannedThrow: android.media.audiofx.AudioEffect#getParameter(int, byte[]):
+    
+BannedThrow: android.media.audiofx.AudioEffect#getParameter(int, int[]):
+    
+BannedThrow: android.media.audiofx.AudioEffect#getParameter(int, short[]):
+    
+BannedThrow: android.media.audiofx.AudioEffect#getParameter(int[], short[]):
+    
+BannedThrow: android.media.audiofx.AudioEffect#setParameter(byte[], byte[]):
+    
+BannedThrow: android.media.audiofx.AudioEffect#setParameter(int, byte[]):
+    
+BannedThrow: android.media.audiofx.AudioEffect#setParameter(int, int):
+    
+BannedThrow: android.media.audiofx.AudioEffect#setParameter(int, short):
+    
+BannedThrow: android.media.audiofx.AudioEffect#setParameter(int[], byte[]):
+    
+BannedThrow: android.media.audiofx.AudioEffect#setParameter(int[], int[]):
+    
+BannedThrow: android.media.audiopolicy.AudioMix.Builder#Builder(android.media.audiopolicy.AudioMixingRule):
+    
+BannedThrow: android.media.audiopolicy.AudioMix.Builder#build():
+    
+BannedThrow: android.media.audiopolicy.AudioMix.Builder#setDevice(android.media.AudioDeviceInfo):
+    
+BannedThrow: android.media.audiopolicy.AudioMix.Builder#setFormat(android.media.AudioFormat):
+    
+BannedThrow: android.media.audiopolicy.AudioMix.Builder#setRouteFlags(int):
+    
+BannedThrow: android.media.audiopolicy.AudioMixingRule.Builder#addMixRule(int, Object):
+    
+BannedThrow: android.media.audiopolicy.AudioMixingRule.Builder#addRule(android.media.AudioAttributes, int):
+    
+BannedThrow: android.media.audiopolicy.AudioMixingRule.Builder#excludeMixRule(int, Object):
+    
+BannedThrow: android.media.audiopolicy.AudioMixingRule.Builder#excludeRule(android.media.AudioAttributes, int):
+    
+BannedThrow: android.media.audiopolicy.AudioPolicy#createAudioRecordSink(android.media.audiopolicy.AudioMix):
+    
+BannedThrow: android.media.audiopolicy.AudioPolicy#createAudioTrackSource(android.media.audiopolicy.AudioMix):
+    
+BannedThrow: android.media.audiopolicy.AudioPolicy#setFocusDuckingBehavior(int):
+    
+BannedThrow: android.media.audiopolicy.AudioPolicy.Builder#addMix(android.media.audiopolicy.AudioMix):
+    
+BannedThrow: android.media.audiopolicy.AudioPolicy.Builder#setLooper(android.os.Looper):
+    
+BannedThrow: android.os.HwBinder#getService(String, String):
+    
+BannedThrow: android.os.HwBinder#getService(String, String, boolean):
+    
+BannedThrow: android.os.Process#getThreadScheduler(int):
+    
+
+
+CallbackInterface: android.app.prediction.AppPredictor.Callback:
+    
+CallbackInterface: android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback:
+    
+CallbackInterface: android.widget.Magnifier.Callback:
+    
+
+
+CallbackMethodName: android.os.RemoteCallback:
+    
+
+
+ConcreteCollection: android.content.AutofillOptions#disabledActivities:
+    
+ConcreteCollection: android.content.AutofillOptions#whitelistedActivitiesForAugmentedAutofill:
+    
+ConcreteCollection: android.content.ContentCaptureOptions#ContentCaptureOptions(int, int, int, int, int, android.util.ArraySet<android.content.ComponentName>) parameter #5:
+    
+ConcreteCollection: android.content.ContentCaptureOptions#whitelistedComponents:
+    
+ConcreteCollection: android.database.sqlite.SQLiteDebug.PagerStats#dbStats:
+    
+ConcreteCollection: android.os.HwParcel#readBoolVector():
+    
+ConcreteCollection: android.os.HwParcel#readDoubleVector():
+    
+ConcreteCollection: android.os.HwParcel#readFloatVector():
+    
+ConcreteCollection: android.os.HwParcel#readInt16Vector():
+    
+ConcreteCollection: android.os.HwParcel#readInt32Vector():
+    
+ConcreteCollection: android.os.HwParcel#readInt64Vector():
+    
+ConcreteCollection: android.os.HwParcel#readInt8Vector():
+    
+ConcreteCollection: android.os.HwParcel#readNativeHandleVector():
+    
+ConcreteCollection: android.os.HwParcel#readStringVector():
+    
+ConcreteCollection: android.os.HwParcel#writeBoolVector(java.util.ArrayList<java.lang.Boolean>) parameter #0:
+    
+ConcreteCollection: android.os.HwParcel#writeDoubleVector(java.util.ArrayList<java.lang.Double>) parameter #0:
+    
+ConcreteCollection: android.os.HwParcel#writeFloatVector(java.util.ArrayList<java.lang.Float>) parameter #0:
+    
+ConcreteCollection: android.os.HwParcel#writeInt16Vector(java.util.ArrayList<java.lang.Short>) parameter #0:
+    
+ConcreteCollection: android.os.HwParcel#writeInt32Vector(java.util.ArrayList<java.lang.Integer>) parameter #0:
+    
+ConcreteCollection: android.os.HwParcel#writeInt64Vector(java.util.ArrayList<java.lang.Long>) parameter #0:
+    
+ConcreteCollection: android.os.HwParcel#writeInt8Vector(java.util.ArrayList<java.lang.Byte>) parameter #0:
+    
+ConcreteCollection: android.os.HwParcel#writeNativeHandleVector(java.util.ArrayList<android.os.NativeHandle>) parameter #0:
+    
+ConcreteCollection: android.os.HwParcel#writeStringVector(java.util.ArrayList<java.lang.String>) parameter #0:
+    
+ConcreteCollection: android.service.autofill.CompositeUserData#getFieldClassificationAlgorithms():
+    
+ConcreteCollection: android.service.autofill.CompositeUserData#getFieldClassificationArgs():
+    
+ConcreteCollection: android.service.autofill.InternalTransformation#batchApply(android.service.autofill.ValueFinder, android.widget.RemoteViews, java.util.ArrayList<android.util.Pair<java.lang.Integer,android.service.autofill.InternalTransformation>>) parameter #2:
+    
+ConcreteCollection: android.service.autofill.UserData#getFieldClassificationAlgorithms():
+    
+
+
+ContextFirst: android.os.VibrationEffect#get(android.net.Uri, android.content.Context) parameter #1:
+    
+
+
+ContextNameSuffix: android.telephony.mbms.vendor.MbmsGroupCallServiceBase:
+    
+
+
+EndsWithImpl: android.view.contentcapture.ViewNode.ViewStructureImpl:
+    
+
+
+Enum: android.view.inspector.InspectableProperty.ValueType:
+    
+
+
+EqualsAndHashCode: android.app.prediction.AppPredictionContext#equals(Object):
+    
+EqualsAndHashCode: android.app.prediction.AppTarget#equals(Object):
+    
+EqualsAndHashCode: android.app.prediction.AppTargetEvent#equals(Object):
+    
+EqualsAndHashCode: android.net.apf.ApfCapabilities#equals(Object):
+    
+EqualsAndHashCode: android.net.metrics.ApfProgramEvent#equals(Object):
+    
+EqualsAndHashCode: android.net.metrics.ApfStats#equals(Object):
+    
+EqualsAndHashCode: android.net.metrics.DhcpClientEvent#equals(Object):
+    
+EqualsAndHashCode: android.net.metrics.IpManagerEvent#equals(Object):
+    
+EqualsAndHashCode: android.net.metrics.IpReachabilityEvent#equals(Object):
+    
+EqualsAndHashCode: android.net.metrics.NetworkEvent#equals(Object):
+    
+EqualsAndHashCode: android.net.metrics.RaEvent#equals(Object):
+    
+EqualsAndHashCode: android.net.metrics.ValidationProbeEvent#equals(Object):
+    
+EqualsAndHashCode: android.os.IncidentManager.PendingReport#equals(Object):
+    
+EqualsAndHashCode: android.os.StrictMode.ViolationInfo#hashCode():
+    
+
+
+ExecutorRegistration: android.content.pm.PackageManager#addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener):
+    
+ExecutorRegistration: android.hardware.camera2.CameraDevice#createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler):
+    
+ExecutorRegistration: android.media.audiofx.AudioEffect#setParameterListener(android.media.audiofx.AudioEffect.OnParameterChangeListener):
+    
+ExecutorRegistration: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyFocusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener):
+    
+ExecutorRegistration: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyStatusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener):
+    
+ExecutorRegistration: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyVolumeCallback(android.media.audiopolicy.AudioPolicy.AudioPolicyVolumeCallback):
+    
+ExecutorRegistration: android.os.IncidentManager#cancelAuthorization(android.os.IncidentManager.AuthListener):
+    
+ExecutorRegistration: android.os.IncidentManager#requestAuthorization(int, String, int, android.os.IncidentManager.AuthListener):
+    
+ExecutorRegistration: android.os.RemoteCallback#RemoteCallback(android.os.RemoteCallback.OnResultListener, android.os.Handler):
+    
+ExecutorRegistration: android.permission.PermissionControllerManager#getAppPermissions(String, android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, android.os.Handler):
+    
+ExecutorRegistration: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener):
+    
+ExecutorRegistration: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener):
+    
+ExecutorRegistration: android.telephony.mbms.vendor.MbmsDownloadServiceBase#initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback):
+    
+ExecutorRegistration: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int):
+    
+ExecutorRegistration: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#startGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>, android.telephony.mbms.GroupCallCallback):
+    
+ExecutorRegistration: android.telephony.mbms.vendor.MbmsStreamingServiceBase#initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int):
+    
+ExecutorRegistration: android.telephony.mbms.vendor.MbmsStreamingServiceBase#startStreaming(int, String, android.telephony.mbms.StreamingServiceCallback):
+    
+
+
+ForbiddenSuperClass: android.app.AppDetailsActivity:
+    
+
+
+GenericException: android.app.ActivityView#finalize():
+    
+GenericException: android.app.prediction.AppPredictor#finalize():
+    
+GenericException: android.service.autofill.CharSequenceTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int):
+    
+GenericException: android.service.autofill.DateTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int):
+    
+GenericException: android.service.autofill.ImageTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int):
+    
+GenericException: android.service.autofill.augmented.FillWindow#finalize():
+    
+
+
+GetterSetterNames: android.app.NotificationChannel#isBlockableSystem():
+    
+GetterSetterNames: android.app.NotificationChannel#isImportanceLockedByCriticalDeviceFunction():
+    
+GetterSetterNames: android.app.NotificationChannel#isImportanceLockedByOEM():
+    
+GetterSetterNames: android.location.GnssClock#setBiasNanos(double):
+    
+GetterSetterNames: android.location.GnssClock#setBiasUncertaintyNanos(double):
+    
+GetterSetterNames: android.location.GnssClock#setDriftNanosPerSecond(double):
+    
+GetterSetterNames: android.location.GnssClock#setDriftUncertaintyNanosPerSecond(double):
+    
+GetterSetterNames: android.location.GnssClock#setElapsedRealtimeNanos(long):
+    
+GetterSetterNames: android.location.GnssClock#setElapsedRealtimeUncertaintyNanos(double):
+    
+GetterSetterNames: android.location.GnssClock#setFullBiasNanos(long):
+    
+GetterSetterNames: android.location.GnssClock#setLeapSecond(int):
+    
+GetterSetterNames: android.location.GnssClock#setTimeUncertaintyNanos(double):
+    
+GetterSetterNames: android.location.GnssMeasurement#setCarrierFrequencyHz(float):
+    
+GetterSetterNames: android.location.GnssMeasurement#setCodeType(String):
+    
+GetterSetterNames: android.location.GnssMeasurement#setSnrInDb(double):
+    
+GetterSetterNames: android.location.LocationRequest#isLocationSettingsIgnored():
+    
+GetterSetterNames: android.location.LocationRequest#isLowPowerMode():
+    
+GetterSetterNames: android.os.IncidentReportArgs#isAll():
+    
+GetterSetterNames: android.service.notification.NotificationStats#setDirectReplied():
+    
+GetterSetterNames: android.service.notification.NotificationStats#setExpanded():
+    
+GetterSetterNames: android.service.notification.NotificationStats#setSeen():
+    
+GetterSetterNames: android.service.notification.NotificationStats#setSnoozed():
+    
+GetterSetterNames: android.service.notification.NotificationStats#setViewedSettings():
+    
+GetterSetterNames: android.view.View#isAutofilled():
+    
+GetterSetterNames: android.view.View#isDefaultFocusHighlightEnabled():
+    
+
+
+IllegalStateException: android.media.audiopolicy.AudioMix.Builder#build():
+    
+
+
+IntentBuilderName: android.app.backup.BackupManager#getConfigurationIntent(String):
+    
+IntentBuilderName: android.app.backup.BackupManager#getDataManagementIntent(String):
+    
+
+
+IntentName: android.provider.Settings.Secure#VOICE_INTERACTION_SERVICE:
+    
+IntentName: android.provider.Telephony.Sms.Intents#SMS_CARRIER_PROVISION_ACTION:
+    
+IntentName: android.service.notification.Adjustment#KEY_CONTEXTUAL_ACTIONS:
+    
+
+
+InterfaceConstant: android.service.autofill.AutofillFieldClassificationService#SERVICE_INTERFACE:
+    
+InterfaceConstant: android.service.autofill.augmented.AugmentedAutofillService#SERVICE_INTERFACE:
+    
+InterfaceConstant: android.service.contentcapture.ContentCaptureService#SERVICE_INTERFACE:
+    
+InterfaceConstant: android.service.notification.NotificationAssistantService#SERVICE_INTERFACE:
+    
+InterfaceConstant: android.telecom.PhoneAccountSuggestionService#SERVICE_INTERFACE:
+    
+
+
+KotlinOperator: android.os.WorkSource#get(int):
+    
+
+
+ListenerInterface: android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener:
+    
+ListenerInterface: android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener:
+    
+ListenerInterface: android.os.IncidentManager.AuthListener:
+    
+
+
+ListenerLast: android.hardware.camera2.CameraDevice#createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) parameter #4:
+    
+ListenerLast: android.location.LocationManager#requestLocationUpdates(android.location.LocationRequest, android.location.LocationListener, android.os.Looper) parameter #2:
+    
+ListenerLast: android.permission.PermissionControllerManager#getAppPermissions(String, android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, android.os.Handler) parameter #2:
+    
+ListenerLast: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int) parameter #1:
+    
+ListenerLast: android.telephony.mbms.vendor.MbmsStreamingServiceBase#initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int) parameter #1:
+    
+
+
+ManagerConstructor: android.content.pm.ShortcutManager#ShortcutManager(android.content.Context):
+    
+
+
+MinMaxConstant: android.os.UserHandle#MIN_SECONDARY_USER_ID:
+    
+MinMaxConstant: android.view.autofill.AutofillManager#MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS:
+    
+
+
+MissingNullability: android.app.Activity#onMovedToDisplay(int, android.content.res.Configuration) parameter #1:
+    
+MissingNullability: android.app.ActivityManager#addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int) parameter #0:
+    
+MissingNullability: android.app.ActivityManager#alwaysShowUnsupportedCompileSdkWarning(android.content.ComponentName) parameter #0:
+    
+MissingNullability: android.app.ActivityManager#forceStopPackage(String) parameter #0:
+    
+MissingNullability: android.app.ActivityManager#getPackageImportance(String) parameter #0:
+    
+MissingNullability: android.app.ActivityManager#removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener) parameter #0:
+    
+MissingNullability: android.app.ActivityManager#scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int) parameter #0:
+    
+MissingNullability: android.app.ActivityManager.TaskDescription#getIconFilename():
+    
+MissingNullability: android.app.ActivityTaskManager#clearLaunchParamsForPackages(java.util.List<java.lang.String>) parameter #0:
+    
+MissingNullability: android.app.ActivityTaskManager#listAllStacks():
+    
+MissingNullability: android.app.ActivityTaskManager#moveTopActivityToPinnedStack(int, android.graphics.Rect) parameter #1:
+    
+MissingNullability: android.app.ActivityTaskManager#removeStacksInWindowingModes(int[]) parameter #0:
+    
+MissingNullability: android.app.ActivityTaskManager#removeStacksWithActivityTypes(int[]) parameter #0:
+    
+MissingNullability: android.app.ActivityTaskManager#resizeDockedStack(android.graphics.Rect, android.graphics.Rect) parameter #0:
+    
+MissingNullability: android.app.ActivityTaskManager#resizeDockedStack(android.graphics.Rect, android.graphics.Rect) parameter #1:
+    
+MissingNullability: android.app.ActivityTaskManager#resizePinnedStack(int, android.graphics.Rect, boolean) parameter #1:
+    
+MissingNullability: android.app.ActivityTaskManager#resizeTask(int, android.graphics.Rect) parameter #1:
+    
+MissingNullability: android.app.ActivityTaskManager#setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect, boolean) parameter #4:
+    
+MissingNullability: android.app.ActivityTaskManager#supportsMultiWindow(android.content.Context) parameter #0:
+    
+MissingNullability: android.app.ActivityTaskManager#supportsSplitScreenMultiWindow(android.content.Context) parameter #0:
+    
+MissingNullability: android.app.ActivityView#ActivityView(android.content.Context) parameter #0:
+    
+MissingNullability: android.app.ActivityView#ActivityView(android.content.Context, android.util.AttributeSet) parameter #0:
+    
+MissingNullability: android.app.ActivityView#ActivityView(android.content.Context, android.util.AttributeSet) parameter #1:
+    
+MissingNullability: android.app.ActivityView#ActivityView(android.content.Context, android.util.AttributeSet, int) parameter #0:
+    
+MissingNullability: android.app.ActivityView#ActivityView(android.content.Context, android.util.AttributeSet, int) parameter #1:
+    
+MissingNullability: android.app.ActivityView#ActivityView(android.content.Context, android.util.AttributeSet, int, boolean) parameter #0:
+    
+MissingNullability: android.app.ActivityView#ActivityView(android.content.Context, android.util.AttributeSet, int, boolean) parameter #1:
+    
+MissingNullability: android.app.ActivityView#gatherTransparentRegion(android.graphics.Region) parameter #0:
+    
+MissingNullability: android.app.ActivityView#onVisibilityChanged(android.view.View, int) parameter #0:
+    
+MissingNullability: android.app.ActivityView#setCallback(android.app.ActivityView.StateCallback) parameter #0:
+    
+MissingNullability: android.app.ActivityView#setForwardedInsets(android.graphics.Insets) parameter #0:
+    
+MissingNullability: android.app.ActivityView#startActivity(android.content.Intent, android.os.UserHandle) parameter #1:
+    
+MissingNullability: android.app.ActivityView.StateCallback#onActivityViewDestroyed(android.app.ActivityView) parameter #0:
+    
+MissingNullability: android.app.ActivityView.StateCallback#onActivityViewReady(android.app.ActivityView) parameter #0:
+    
+MissingNullability: android.app.ActivityView.StateCallback#onTaskCreated(int, android.content.ComponentName) parameter #1:
+    
+MissingNullability: android.app.AppDetailsActivity#onCreate(android.os.Bundle) parameter #0:
+    
+MissingNullability: android.app.AppOpsManager#getOpStrs():
+    
+MissingNullability: android.app.AppOpsManager#isOperationActive(int, int, String) parameter #2:
+    
+MissingNullability: android.app.AppOpsManager#opToPermission(int):
+    
+MissingNullability: android.app.AppOpsManager#permissionToOpCode(String) parameter #0:
+    
+MissingNullability: android.app.AppOpsManager#setMode(String, int, String, int) parameter #0:
+    
+MissingNullability: android.app.AppOpsManager#setMode(String, int, String, int) parameter #2:
+    
+MissingNullability: android.app.AppOpsManager#setMode(int, int, String, int) parameter #2:
+    
+MissingNullability: android.app.AppOpsManager#setUidMode(String, int, int) parameter #0:
+    
+MissingNullability: android.app.AppOpsManager.HistoricalOp#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.app.AppOpsManager.HistoricalOps#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.app.AppOpsManager.HistoricalUidOps#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.app.AppOpsManager.OpEntry#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.app.NotificationManager#allowAssistantAdjustment(String) parameter #0:
+    
+MissingNullability: android.app.NotificationManager#disallowAssistantAdjustment(String) parameter #0:
+    
+MissingNullability: android.app.NotificationManager#getEffectsSuppressor():
+    
+MissingNullability: android.app.NotificationManager#matchesCallFilter(android.os.Bundle) parameter #0:
+    
+MissingNullability: android.app.PictureInPictureParams#getActions():
+    
+MissingNullability: android.app.PictureInPictureParams#getSourceRectHint():
+    
+MissingNullability: android.app.TimePickerDialog#getTimePicker():
+    
+MissingNullability: android.app.UiAutomation#executeShellCommandRw(String):
+    
+MissingNullability: android.app.UiAutomation#executeShellCommandRw(String) parameter #0:
+    
+MissingNullability: android.app.UiAutomation#grantRuntimePermission(String, String, android.os.UserHandle) parameter #0:
+    
+MissingNullability: android.app.UiAutomation#grantRuntimePermission(String, String, android.os.UserHandle) parameter #1:
+    
+MissingNullability: android.app.UiAutomation#grantRuntimePermission(String, String, android.os.UserHandle) parameter #2:
+    
+MissingNullability: android.app.UiAutomation#revokeRuntimePermission(String, String, android.os.UserHandle) parameter #0:
+    
+MissingNullability: android.app.UiAutomation#revokeRuntimePermission(String, String, android.os.UserHandle) parameter #1:
+    
+MissingNullability: android.app.UiAutomation#revokeRuntimePermission(String, String, android.os.UserHandle) parameter #2:
+    
+MissingNullability: android.app.WallpaperManager#setWallpaperComponent(android.content.ComponentName) parameter #0:
+    
+MissingNullability: android.app.WindowConfiguration#compareTo(android.app.WindowConfiguration) parameter #0:
+    
+MissingNullability: android.app.WindowConfiguration#getAppBounds():
+    
+MissingNullability: android.app.WindowConfiguration#getBounds():
+    
+MissingNullability: android.app.WindowConfiguration#setAppBounds(android.graphics.Rect) parameter #0:
+    
+MissingNullability: android.app.WindowConfiguration#setBounds(android.graphics.Rect) parameter #0:
+    
+MissingNullability: android.app.WindowConfiguration#setTo(android.app.WindowConfiguration) parameter #0:
+    
+MissingNullability: android.app.WindowConfiguration#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.app.admin.DevicePolicyManager#getOwnerInstalledCaCerts(android.os.UserHandle):
+    
+MissingNullability: android.app.admin.SecurityLog.SecurityEvent#SecurityEvent(long, byte[]) parameter #1:
+    
+MissingNullability: android.app.backup.BackupManager#getConfigurationIntent(String):
+    
+MissingNullability: android.app.backup.BackupManager#getConfigurationIntent(String) parameter #0:
+    
+MissingNullability: android.app.backup.BackupManager#getDataManagementIntent(String):
+    
+MissingNullability: android.app.backup.BackupManager#getDataManagementIntent(String) parameter #0:
+    
+MissingNullability: android.app.backup.BackupManager#getDestinationString(String):
+    
+MissingNullability: android.app.backup.BackupManager#getDestinationString(String) parameter #0:
+    
+MissingNullability: android.app.prediction.AppPredictionSessionId#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.app.prediction.AppPredictor#getSessionId():
+    
+MissingNullability: android.app.prediction.AppTarget#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.app.prediction.AppTargetEvent#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.app.prediction.AppTargetId#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.content.AutofillOptions#forWhitelistingItself():
+    
+MissingNullability: android.content.AutofillOptions#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.content.ContentCaptureOptions#forWhitelistingItself():
+    
+MissingNullability: android.content.ContentCaptureOptions#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.content.ContentResolver#getSyncAdapterPackagesForAuthorityAsUser(String, int):
+    
+MissingNullability: android.content.ContentResolver#getSyncAdapterPackagesForAuthorityAsUser(String, int) parameter #0:
+    
+MissingNullability: android.content.Context#getDisplay():
+    
+MissingNullability: android.content.Context#getUser():
+    
+MissingNullability: android.content.ContextWrapper#getDisplay():
+    
+MissingNullability: android.content.ContextWrapper#setContentCaptureOptions(android.content.ContentCaptureOptions) parameter #0:
+    
+MissingNullability: android.content.pm.ActivityInfo#isTranslucentOrFloating(android.content.res.TypedArray) parameter #0:
+    
+MissingNullability: android.content.pm.LauncherApps#LauncherApps(android.content.Context) parameter #0:
+    
+MissingNullability: android.content.pm.PackageInstaller.SessionParams#setGrantedRuntimePermissions(String[]) parameter #0:
+    
+MissingNullability: android.content.pm.PackageManager#getNamesForUids(int[]) parameter #0:
+    
+MissingNullability: android.content.pm.ShortcutManager#ShortcutManager(android.content.Context) parameter #0:
+    
+MissingNullability: android.content.res.AssetManager#getOverlayablesToString(String) parameter #0:
+    
+MissingNullability: android.content.res.Configuration#windowConfiguration:
+    
+MissingNullability: android.content.rollback.PackageRollbackInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.content.rollback.RollbackInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.database.sqlite.SQLiteDebug#dump(android.util.Printer, String[]) parameter #0:
+    
+MissingNullability: android.database.sqlite.SQLiteDebug#dump(android.util.Printer, String[]) parameter #1:
+    
+MissingNullability: android.database.sqlite.SQLiteDebug#getDatabaseInfo():
+    
+MissingNullability: android.database.sqlite.SQLiteDebug.DbStats#DbStats(String, long, long, int, int, int, int) parameter #0:
+    
+MissingNullability: android.database.sqlite.SQLiteDebug.DbStats#cache:
+    
+MissingNullability: android.database.sqlite.SQLiteDebug.DbStats#dbName:
+    
+MissingNullability: android.database.sqlite.SQLiteDebug.PagerStats#dbStats:
+    
+MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#SQLiteDirectCursorDriver(android.database.sqlite.SQLiteDatabase, String, String, android.os.CancellationSignal) parameter #0:
+    
+MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#SQLiteDirectCursorDriver(android.database.sqlite.SQLiteDatabase, String, String, android.os.CancellationSignal) parameter #1:
+    
+MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#SQLiteDirectCursorDriver(android.database.sqlite.SQLiteDatabase, String, String, android.os.CancellationSignal) parameter #2:
+    
+MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#SQLiteDirectCursorDriver(android.database.sqlite.SQLiteDatabase, String, String, android.os.CancellationSignal) parameter #3:
+    
+MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#cursorRequeried(android.database.Cursor) parameter #0:
+    
+MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]):
+    
+MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]) parameter #0:
+    
+MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]) parameter #1:
+    
+MissingNullability: android.database.sqlite.SQLiteDirectCursorDriver#setBindArguments(String[]) parameter #0:
+    
+MissingNullability: android.database.sqlite.SQLiteGlobal#getDefaultJournalMode():
+    
+MissingNullability: android.database.sqlite.SQLiteGlobal#getDefaultSyncMode():
+    
+MissingNullability: android.database.sqlite.SQLiteGlobal#getWALSyncMode():
+    
+MissingNullability: android.graphics.ImageDecoder#createSource(android.content.res.Resources, java.io.InputStream, int) parameter #0:
+    
+MissingNullability: android.graphics.ImageDecoder#createSource(android.content.res.Resources, java.io.InputStream, int) parameter #1:
+    
+MissingNullability: android.graphics.drawable.AdaptiveIconDrawable#getSafeZone():
+    
+MissingNullability: android.graphics.drawable.ColorDrawable#getXfermode():
+    
+MissingNullability: android.hardware.camera2.CameraDevice#createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) parameter #0:
+    
+MissingNullability: android.hardware.camera2.CameraManager#getCameraIdListNoLazy():
+    
+MissingNullability: android.hardware.display.AmbientBrightnessDayStats#getBucketBoundaries():
+    
+MissingNullability: android.hardware.display.AmbientBrightnessDayStats#getLocalDate():
+    
+MissingNullability: android.hardware.display.AmbientBrightnessDayStats#getStats():
+    
+MissingNullability: android.hardware.display.AmbientBrightnessDayStats#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.hardware.display.AmbientDisplayConfiguration#AmbientDisplayConfiguration(android.content.Context) parameter #0:
+    
+MissingNullability: android.hardware.display.BrightnessChangeEvent#luxTimestamps:
+    
+MissingNullability: android.hardware.display.BrightnessChangeEvent#luxValues:
+    
+MissingNullability: android.hardware.display.BrightnessChangeEvent#packageName:
+    
+MissingNullability: android.hardware.display.BrightnessChangeEvent#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.hardware.display.BrightnessConfiguration#getCurve():
+    
+MissingNullability: android.hardware.display.BrightnessConfiguration#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.hardware.display.BrightnessConfiguration.Builder#Builder(float[], float[]) parameter #0:
+    
+MissingNullability: android.hardware.display.BrightnessConfiguration.Builder#Builder(float[], float[]) parameter #1:
+    
+MissingNullability: android.hardware.display.BrightnessCorrection#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.hardware.display.DisplayManager#getAmbientBrightnessStats():
+    
+MissingNullability: android.hardware.display.DisplayManager#getBrightnessConfiguration():
+    
+MissingNullability: android.hardware.display.DisplayManager#getBrightnessEvents():
+    
+MissingNullability: android.hardware.display.DisplayManager#getStableDisplaySize():
+    
+MissingNullability: android.hardware.display.DisplayManager#setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration) parameter #0:
+    
+MissingNullability: android.location.GnssClock#set(android.location.GnssClock) parameter #0:
+    
+MissingNullability: android.location.GnssMeasurement#set(android.location.GnssMeasurement) parameter #0:
+    
+MissingNullability: android.location.GnssMeasurementsEvent#GnssMeasurementsEvent(android.location.GnssClock, android.location.GnssMeasurement[]) parameter #0:
+    
+MissingNullability: android.location.GnssMeasurementsEvent#GnssMeasurementsEvent(android.location.GnssClock, android.location.GnssMeasurement[]) parameter #1:
+    
+MissingNullability: android.location.GnssNavigationMessage#set(android.location.GnssNavigationMessage) parameter #0:
+    
+MissingNullability: android.location.GnssNavigationMessage#setData(byte[]) parameter #0:
+    
+MissingNullability: android.location.LocationManager#getTestProviderCurrentRequests(String) parameter #0:
+    
+MissingNullability: android.location.LocationRequest#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.media.AudioFocusInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String) parameter #3:
+    
+MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String) parameter #4:
+    
+MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String) parameter #6:
+    
+MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #10:
+    
+MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #11:
+    
+MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #3:
+    
+MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #4:
+    
+MissingNullability: android.media.AudioRecordingConfiguration#AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String, int, boolean, int, android.media.audiofx.AudioEffect.Descriptor[], android.media.audiofx.AudioEffect.Descriptor[]) parameter #6:
+    
+MissingNullability: android.media.PlaybackParams#setAudioStretchMode(int):
+    
+MissingNullability: android.media.audiofx.AudioEffect#EFFECT_TYPE_NULL:
+    
+MissingNullability: android.media.audiofx.AudioEffect#byteArrayToInt(byte[]) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect#byteArrayToShort(byte[]) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect#getParameter(byte[], byte[]) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect#getParameter(byte[], byte[]) parameter #1:
+    
+MissingNullability: android.media.audiofx.AudioEffect#getParameter(int, byte[]) parameter #1:
+    
+MissingNullability: android.media.audiofx.AudioEffect#getParameter(int, int[]) parameter #1:
+    
+MissingNullability: android.media.audiofx.AudioEffect#getParameter(int, short[]) parameter #1:
+    
+MissingNullability: android.media.audiofx.AudioEffect#getParameter(int[], short[]) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect#getParameter(int[], short[]) parameter #1:
+    
+MissingNullability: android.media.audiofx.AudioEffect#intToByteArray(int):
+    
+MissingNullability: android.media.audiofx.AudioEffect#isEffectTypeAvailable(java.util.UUID) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect#setParameter(byte[], byte[]) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect#setParameter(byte[], byte[]) parameter #1:
+    
+MissingNullability: android.media.audiofx.AudioEffect#setParameter(int, byte[]) parameter #1:
+    
+MissingNullability: android.media.audiofx.AudioEffect#setParameter(int[], byte[]) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect#setParameter(int[], byte[]) parameter #1:
+    
+MissingNullability: android.media.audiofx.AudioEffect#setParameter(int[], int[]) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect#setParameter(int[], int[]) parameter #1:
+    
+MissingNullability: android.media.audiofx.AudioEffect#setParameterListener(android.media.audiofx.AudioEffect.OnParameterChangeListener) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect#shortToByteArray(short):
+    
+MissingNullability: android.media.audiofx.AudioEffect.Descriptor#Descriptor(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect.Descriptor#writeToParcel(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect.OnParameterChangeListener#onParameterChange(android.media.audiofx.AudioEffect, int, byte[], byte[]) parameter #0:
+    
+MissingNullability: android.media.audiofx.AudioEffect.OnParameterChangeListener#onParameterChange(android.media.audiofx.AudioEffect, int, byte[], byte[]) parameter #2:
+    
+MissingNullability: android.media.audiofx.AudioEffect.OnParameterChangeListener#onParameterChange(android.media.audiofx.AudioEffect, int, byte[], byte[]) parameter #3:
+    
+MissingNullability: android.media.audiopolicy.AudioMix.Builder#Builder(android.media.audiopolicy.AudioMixingRule) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioMix.Builder#build():
+    
+MissingNullability: android.media.audiopolicy.AudioMix.Builder#setDevice(android.media.AudioDeviceInfo):
+    
+MissingNullability: android.media.audiopolicy.AudioMix.Builder#setFormat(android.media.AudioFormat):
+    
+MissingNullability: android.media.audiopolicy.AudioMix.Builder#setFormat(android.media.AudioFormat) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioMix.Builder#setRouteFlags(int):
+    
+MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#addMixRule(int, Object):
+    
+MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#addMixRule(int, Object) parameter #1:
+    
+MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#addRule(android.media.AudioAttributes, int):
+    
+MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#addRule(android.media.AudioAttributes, int) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#build():
+    
+MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#excludeMixRule(int, Object):
+    
+MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#excludeMixRule(int, Object) parameter #1:
+    
+MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#excludeRule(android.media.AudioAttributes, int):
+    
+MissingNullability: android.media.audiopolicy.AudioMixingRule.Builder#excludeRule(android.media.AudioAttributes, int) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy#createAudioRecordSink(android.media.audiopolicy.AudioMix):
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy#createAudioRecordSink(android.media.audiopolicy.AudioMix) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy#createAudioTrackSource(android.media.audiopolicy.AudioMix):
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy#createAudioTrackSource(android.media.audiopolicy.AudioMix) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy#setRegistration(String) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy#toLogFriendlyString():
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener#onAudioFocusAbandon(android.media.AudioFocusInfo) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener#onAudioFocusGrant(android.media.AudioFocusInfo, int) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener#onAudioFocusLoss(android.media.AudioFocusInfo, boolean) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(android.media.AudioFocusInfo, int) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener#onMixStateUpdate(android.media.audiopolicy.AudioMix) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy.Builder#Builder(android.content.Context) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyFocusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener) parameter #0:
+    
+MissingNullability: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyStatusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener) parameter #0:
+    
+MissingNullability: android.metrics.LogMaker#LogMaker(Object[]) parameter #0:
+    
+MissingNullability: android.metrics.LogMaker#addTaggedData(int, Object):
+    
+MissingNullability: android.metrics.LogMaker#addTaggedData(int, Object) parameter #1:
+    
+MissingNullability: android.metrics.LogMaker#clearCategory():
+    
+MissingNullability: android.metrics.LogMaker#clearPackageName():
+    
+MissingNullability: android.metrics.LogMaker#clearSubtype():
+    
+MissingNullability: android.metrics.LogMaker#clearTaggedData(int):
+    
+MissingNullability: android.metrics.LogMaker#clearType():
+    
+MissingNullability: android.metrics.LogMaker#deserialize(Object[]) parameter #0:
+    
+MissingNullability: android.metrics.LogMaker#getCounterName():
+    
+MissingNullability: android.metrics.LogMaker#getPackageName():
+    
+MissingNullability: android.metrics.LogMaker#getTaggedData(int):
+    
+MissingNullability: android.metrics.LogMaker#isSubsetOf(android.metrics.LogMaker) parameter #0:
+    
+MissingNullability: android.metrics.LogMaker#isValidValue(Object) parameter #0:
+    
+MissingNullability: android.metrics.LogMaker#serialize():
+    
+MissingNullability: android.metrics.LogMaker#setCategory(int):
+    
+MissingNullability: android.metrics.LogMaker#setPackageName(String):
+    
+MissingNullability: android.metrics.LogMaker#setPackageName(String) parameter #0:
+    
+MissingNullability: android.metrics.LogMaker#setSubtype(int):
+    
+MissingNullability: android.metrics.LogMaker#setType(int):
+    
+MissingNullability: android.metrics.MetricsReader#next():
+    
+MissingNullability: android.net.NetworkCapabilities#getCapabilities():
+    
+MissingNullability: android.net.StaticIpConfiguration#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.net.TestNetworkInterface#CREATOR:
+    
+MissingNullability: android.net.TestNetworkInterface#TestNetworkInterface(android.os.ParcelFileDescriptor, String) parameter #0:
+    
+MissingNullability: android.net.TestNetworkInterface#TestNetworkInterface(android.os.ParcelFileDescriptor, String) parameter #1:
+    
+MissingNullability: android.net.TestNetworkInterface#getFileDescriptor():
+    
+MissingNullability: android.net.TestNetworkInterface#getInterfaceName():
+    
+MissingNullability: android.net.TestNetworkInterface#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.net.TestNetworkManager#createTapInterface():
+    
+MissingNullability: android.net.TestNetworkManager#createTunInterface(android.net.LinkAddress[]):
+    
+MissingNullability: android.net.apf.ApfCapabilities#CREATOR:
+    
+MissingNullability: android.net.apf.ApfCapabilities#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.net.metrics.DhcpClientEvent.Builder#setMsg(String) parameter #0:
+    
+MissingNullability: android.os.Build#is64BitAbi(String) parameter #0:
+    
+MissingNullability: android.os.Build.VERSION#ACTIVE_CODENAMES:
+    
+MissingNullability: android.os.Environment#buildPath(java.io.File, java.lang.String...):
+    
+MissingNullability: android.os.Environment#buildPath(java.io.File, java.lang.String...) parameter #0:
+    
+MissingNullability: android.os.Environment#buildPath(java.io.File, java.lang.String...) parameter #1:
+    
+MissingNullability: android.os.FileUtils#contains(java.io.File, java.io.File) parameter #0:
+    
+MissingNullability: android.os.FileUtils#contains(java.io.File, java.io.File) parameter #1:
+    
+MissingNullability: android.os.HwBinder#getService(String, String):
+    
+MissingNullability: android.os.HwBinder#getService(String, String) parameter #0:
+    
+MissingNullability: android.os.HwBinder#getService(String, String) parameter #1:
+    
+MissingNullability: android.os.HwBinder#getService(String, String, boolean):
+    
+MissingNullability: android.os.HwBinder#getService(String, String, boolean) parameter #0:
+    
+MissingNullability: android.os.HwBinder#getService(String, String, boolean) parameter #1:
+    
+MissingNullability: android.os.HwBinder#onTransact(int, android.os.HwParcel, android.os.HwParcel, int) parameter #1:
+    
+MissingNullability: android.os.HwBinder#onTransact(int, android.os.HwParcel, android.os.HwParcel, int) parameter #2:
+    
+MissingNullability: android.os.HwBinder#registerService(String) parameter #0:
+    
+MissingNullability: android.os.HwBinder#transact(int, android.os.HwParcel, android.os.HwParcel, int) parameter #1:
+    
+MissingNullability: android.os.HwBinder#transact(int, android.os.HwParcel, android.os.HwParcel, int) parameter #2:
+    
+MissingNullability: android.os.HwBlob#copyToBoolArray(long, boolean[], int) parameter #1:
+    
+MissingNullability: android.os.HwBlob#copyToDoubleArray(long, double[], int) parameter #1:
+    
+MissingNullability: android.os.HwBlob#copyToFloatArray(long, float[], int) parameter #1:
+    
+MissingNullability: android.os.HwBlob#copyToInt16Array(long, short[], int) parameter #1:
+    
+MissingNullability: android.os.HwBlob#copyToInt32Array(long, int[], int) parameter #1:
+    
+MissingNullability: android.os.HwBlob#copyToInt64Array(long, long[], int) parameter #1:
+    
+MissingNullability: android.os.HwBlob#copyToInt8Array(long, byte[], int) parameter #1:
+    
+MissingNullability: android.os.HwBlob#getString(long):
+    
+MissingNullability: android.os.HwBlob#putBlob(long, android.os.HwBlob) parameter #1:
+    
+MissingNullability: android.os.HwBlob#putBoolArray(long, boolean[]) parameter #1:
+    
+MissingNullability: android.os.HwBlob#putDoubleArray(long, double[]) parameter #1:
+    
+MissingNullability: android.os.HwBlob#putFloatArray(long, float[]) parameter #1:
+    
+MissingNullability: android.os.HwBlob#putInt16Array(long, short[]) parameter #1:
+    
+MissingNullability: android.os.HwBlob#putInt32Array(long, int[]) parameter #1:
+    
+MissingNullability: android.os.HwBlob#putInt64Array(long, long[]) parameter #1:
+    
+MissingNullability: android.os.HwBlob#putInt8Array(long, byte[]) parameter #1:
+    
+MissingNullability: android.os.HwBlob#putString(long, String) parameter #1:
+    
+MissingNullability: android.os.HwBlob#wrapArray(boolean[]):
+    
+MissingNullability: android.os.HwBlob#wrapArray(byte[]):
+    
+MissingNullability: android.os.HwBlob#wrapArray(double[]):
+    
+MissingNullability: android.os.HwBlob#wrapArray(float[]):
+    
+MissingNullability: android.os.HwBlob#wrapArray(int[]):
+    
+MissingNullability: android.os.HwBlob#wrapArray(long[]):
+    
+MissingNullability: android.os.HwBlob#wrapArray(short[]):
+    
+MissingNullability: android.os.HwParcel#enforceInterface(String) parameter #0:
+    
+MissingNullability: android.os.HwParcel#readBoolVector():
+    
+MissingNullability: android.os.HwParcel#readBuffer(long):
+    
+MissingNullability: android.os.HwParcel#readDoubleVector():
+    
+MissingNullability: android.os.HwParcel#readEmbeddedBuffer(long, long, long, boolean):
+    
+MissingNullability: android.os.HwParcel#readFloatVector():
+    
+MissingNullability: android.os.HwParcel#readInt16Vector():
+    
+MissingNullability: android.os.HwParcel#readInt32Vector():
+    
+MissingNullability: android.os.HwParcel#readInt64Vector():
+    
+MissingNullability: android.os.HwParcel#readInt8Vector():
+    
+MissingNullability: android.os.HwParcel#readString():
+    
+MissingNullability: android.os.HwParcel#readStringVector():
+    
+MissingNullability: android.os.HwParcel#readStrongBinder():
+    
+MissingNullability: android.os.HwParcel#writeBoolVector(java.util.ArrayList<java.lang.Boolean>) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeBuffer(android.os.HwBlob) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeDoubleVector(java.util.ArrayList<java.lang.Double>) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeFloatVector(java.util.ArrayList<java.lang.Float>) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeInt16Vector(java.util.ArrayList<java.lang.Short>) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeInt32Vector(java.util.ArrayList<java.lang.Integer>) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeInt64Vector(java.util.ArrayList<java.lang.Long>) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeInt8Vector(java.util.ArrayList<java.lang.Byte>) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeInterfaceToken(String) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeString(String) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeStringVector(java.util.ArrayList<java.lang.String>) parameter #0:
+    
+MissingNullability: android.os.HwParcel#writeStrongBinder(android.os.IHwBinder) parameter #0:
+    
+MissingNullability: android.os.IHwBinder#linkToDeath(android.os.IHwBinder.DeathRecipient, long) parameter #0:
+    
+MissingNullability: android.os.IHwBinder#queryLocalInterface(String):
+    
+MissingNullability: android.os.IHwBinder#queryLocalInterface(String) parameter #0:
+    
+MissingNullability: android.os.IHwBinder#transact(int, android.os.HwParcel, android.os.HwParcel, int) parameter #1:
+    
+MissingNullability: android.os.IHwBinder#transact(int, android.os.HwParcel, android.os.HwParcel, int) parameter #2:
+    
+MissingNullability: android.os.IHwBinder#unlinkToDeath(android.os.IHwBinder.DeathRecipient) parameter #0:
+    
+MissingNullability: android.os.IHwInterface#asBinder():
+    
+MissingNullability: android.os.IncidentManager#approveReport(android.net.Uri) parameter #0:
+    
+MissingNullability: android.os.IncidentManager#cancelAuthorization(android.os.IncidentManager.AuthListener) parameter #0:
+    
+MissingNullability: android.os.IncidentManager#deleteIncidentReports(android.net.Uri) parameter #0:
+    
+MissingNullability: android.os.IncidentManager#denyReport(android.net.Uri) parameter #0:
+    
+MissingNullability: android.os.IncidentManager#getIncidentReport(android.net.Uri) parameter #0:
+    
+MissingNullability: android.os.IncidentManager#getIncidentReportList(String) parameter #0:
+    
+MissingNullability: android.os.IncidentManager#getPendingReports():
+    
+MissingNullability: android.os.IncidentManager#reportIncident(android.os.IncidentReportArgs) parameter #0:
+    
+MissingNullability: android.os.IncidentManager#requestAuthorization(int, String, int, android.os.IncidentManager.AuthListener) parameter #1:
+    
+MissingNullability: android.os.IncidentManager#requestAuthorization(int, String, int, android.os.IncidentManager.AuthListener) parameter #3:
+    
+MissingNullability: android.os.IncidentManager.IncidentReport#IncidentReport(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.os.IncidentManager.IncidentReport#getInputStream():
+    
+MissingNullability: android.os.IncidentManager.IncidentReport#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.os.IncidentReportArgs#IncidentReportArgs(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.os.IncidentReportArgs#addHeader(byte[]) parameter #0:
+    
+MissingNullability: android.os.IncidentReportArgs#readFromParcel(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.os.IncidentReportArgs#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.os.ParcelFileDescriptor#getFile(java.io.FileDescriptor):
+    
+MissingNullability: android.os.ParcelFileDescriptor#getFile(java.io.FileDescriptor) parameter #0:
+    
+MissingNullability: android.os.RemoteCallback#RemoteCallback(android.os.RemoteCallback.OnResultListener) parameter #0:
+    
+MissingNullability: android.os.RemoteCallback#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.os.StrictMode#setViolationLogger(android.os.StrictMode.ViolationLogger) parameter #0:
+    
+MissingNullability: android.os.StrictMode.ViolationInfo#ViolationInfo(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.os.StrictMode.ViolationInfo#ViolationInfo(android.os.Parcel, boolean) parameter #0:
+    
+MissingNullability: android.os.StrictMode.ViolationInfo#broadcastIntentAction:
+    
+MissingNullability: android.os.StrictMode.ViolationInfo#dump(android.util.Printer, String) parameter #0:
+    
+MissingNullability: android.os.StrictMode.ViolationInfo#dump(android.util.Printer, String) parameter #1:
+    
+MissingNullability: android.os.StrictMode.ViolationInfo#getStackTrace():
+    
+MissingNullability: android.os.StrictMode.ViolationInfo#getViolationClass():
+    
+MissingNullability: android.os.StrictMode.ViolationInfo#getViolationDetails():
+    
+MissingNullability: android.os.StrictMode.ViolationInfo#tags:
+    
+MissingNullability: android.os.StrictMode.ViolationInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.os.StrictMode.ViolationLogger#log(android.os.StrictMode.ViolationInfo) parameter #0:
+    
+MissingNullability: android.os.UserHandle#of(int):
+    
+MissingNullability: android.os.VibrationEffect#RINGTONES:
+    
+MissingNullability: android.os.VibrationEffect#get(android.net.Uri, android.content.Context) parameter #0:
+    
+MissingNullability: android.os.VibrationEffect#get(android.net.Uri, android.content.Context) parameter #1:
+    
+MissingNullability: android.os.VibrationEffect#get(int):
+    
+MissingNullability: android.os.VibrationEffect#get(int, boolean):
+    
+MissingNullability: android.os.VibrationEffect.OneShot#OneShot(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.os.VibrationEffect.OneShot#scale(float, int):
+    
+MissingNullability: android.os.VibrationEffect.OneShot#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.os.VibrationEffect.Prebaked#Prebaked(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.os.VibrationEffect.Prebaked#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.os.VibrationEffect.Waveform#Waveform(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.os.VibrationEffect.Waveform#Waveform(long[], int[], int) parameter #0:
+    
+MissingNullability: android.os.VibrationEffect.Waveform#Waveform(long[], int[], int) parameter #1:
+    
+MissingNullability: android.os.VibrationEffect.Waveform#getAmplitudes():
+    
+MissingNullability: android.os.VibrationEffect.Waveform#getTimings():
+    
+MissingNullability: android.os.VibrationEffect.Waveform#scale(float, int):
+    
+MissingNullability: android.os.VibrationEffect.Waveform#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.os.VintfObject#getHalNamesAndVersions():
+    
+MissingNullability: android.os.VintfObject#getSepolicyVersion():
+    
+MissingNullability: android.os.VintfObject#getTargetFrameworkCompatibilityMatrixVersion():
+    
+MissingNullability: android.os.VintfObject#getVndkSnapshots():
+    
+MissingNullability: android.os.VintfObject#report():
+    
+MissingNullability: android.os.VintfRuntimeInfo#getCpuInfo():
+    
+MissingNullability: android.os.VintfRuntimeInfo#getHardwareId():
+    
+MissingNullability: android.os.VintfRuntimeInfo#getKernelVersion():
+    
+MissingNullability: android.os.VintfRuntimeInfo#getNodeName():
+    
+MissingNullability: android.os.VintfRuntimeInfo#getOsName():
+    
+MissingNullability: android.os.VintfRuntimeInfo#getOsRelease():
+    
+MissingNullability: android.os.VintfRuntimeInfo#getOsVersion():
+    
+MissingNullability: android.os.WorkSource#add(int, String) parameter #1:
+    
+MissingNullability: android.os.WorkSource#addReturningNewbs(android.os.WorkSource) parameter #0:
+    
+MissingNullability: android.os.WorkSource#getName(int):
+    
+MissingNullability: android.os.WorkSource#setReturningDiffs(android.os.WorkSource) parameter #0:
+    
+MissingNullability: android.os.health.HealthKeys.Constants#Constants(Class) parameter #0:
+    
+MissingNullability: android.os.health.HealthKeys.Constants#getDataType():
+    
+MissingNullability: android.os.health.HealthKeys.Constants#getKeys(int):
+    
+MissingNullability: android.os.health.HealthStats#HealthStats(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.os.health.HealthStatsParceler#HealthStatsParceler(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.os.health.HealthStatsParceler#HealthStatsParceler(android.os.health.HealthStatsWriter) parameter #0:
+    
+MissingNullability: android.os.health.HealthStatsParceler#getHealthStats():
+    
+MissingNullability: android.os.health.HealthStatsParceler#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.os.health.HealthStatsWriter#HealthStatsWriter(android.os.health.HealthKeys.Constants) parameter #0:
+    
+MissingNullability: android.os.health.HealthStatsWriter#addMeasurements(int, String, long) parameter #1:
+    
+MissingNullability: android.os.health.HealthStatsWriter#addStats(int, String, android.os.health.HealthStatsWriter) parameter #1:
+    
+MissingNullability: android.os.health.HealthStatsWriter#addStats(int, String, android.os.health.HealthStatsWriter) parameter #2:
+    
+MissingNullability: android.os.health.HealthStatsWriter#addTimers(int, String, android.os.health.TimerStat) parameter #1:
+    
+MissingNullability: android.os.health.HealthStatsWriter#addTimers(int, String, android.os.health.TimerStat) parameter #2:
+    
+MissingNullability: android.os.health.HealthStatsWriter#flattenToParcel(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.os.storage.StorageVolume#getPath():
+    
+MissingNullability: android.permission.RuntimePermissionPresentationInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.provider.CalendarContract.Calendars#SYNC_WRITABLE_COLUMNS:
+    
+MissingNullability: android.provider.CalendarContract.Events#SYNC_WRITABLE_COLUMNS:
+    
+MissingNullability: android.provider.ContactsContract.CommonDataKinds.Phone#ENTERPRISE_CONTENT_URI:
+    
+MissingNullability: android.provider.ContactsContract.RawContactsEntity#CORP_CONTENT_URI:
+    
+MissingNullability: android.provider.DeviceConfig#getProperty(String, String):
+    
+MissingNullability: android.provider.DeviceConfig#getString(String, String, String):
+    
+MissingNullability: android.provider.MediaStore#deleteContributedMedia(android.content.Context, String, android.os.UserHandle) parameter #0:
+    
+MissingNullability: android.provider.MediaStore#deleteContributedMedia(android.content.Context, String, android.os.UserHandle) parameter #1:
+    
+MissingNullability: android.provider.MediaStore#deleteContributedMedia(android.content.Context, String, android.os.UserHandle) parameter #2:
+    
+MissingNullability: android.provider.MediaStore#getContributedMediaSize(android.content.Context, String, android.os.UserHandle) parameter #0:
+    
+MissingNullability: android.provider.MediaStore#getContributedMediaSize(android.content.Context, String, android.os.UserHandle) parameter #1:
+    
+MissingNullability: android.provider.MediaStore#getContributedMediaSize(android.content.Context, String, android.os.UserHandle) parameter #2:
+    
+MissingNullability: android.provider.MediaStore#scanFile(android.content.Context, java.io.File):
+    
+MissingNullability: android.provider.MediaStore#scanFile(android.content.Context, java.io.File) parameter #0:
+    
+MissingNullability: android.provider.MediaStore#scanFile(android.content.Context, java.io.File) parameter #1:
+    
+MissingNullability: android.provider.MediaStore#scanFileFromShell(android.content.Context, java.io.File):
+    
+MissingNullability: android.provider.MediaStore#scanFileFromShell(android.content.Context, java.io.File) parameter #0:
+    
+MissingNullability: android.provider.MediaStore#scanFileFromShell(android.content.Context, java.io.File) parameter #1:
+    
+MissingNullability: android.provider.MediaStore#scanVolume(android.content.Context, java.io.File) parameter #0:
+    
+MissingNullability: android.provider.MediaStore#scanVolume(android.content.Context, java.io.File) parameter #1:
+    
+MissingNullability: android.provider.MediaStore#waitForIdle(android.content.Context) parameter #0:
+    
+MissingNullability: android.security.KeyStoreException#KeyStoreException(int, String) parameter #1:
+    
+MissingNullability: android.security.keystore.AttestationUtils#attestDeviceIds(android.content.Context, int[], byte[]) parameter #0:
+    
+MissingNullability: android.security.keystore.KeyProtection.Builder#setBoundToSpecificSecureUserId(long):
+    
+MissingNullability: android.service.autofill.AutofillFieldClassificationService#onBind(android.content.Intent):
+    
+MissingNullability: android.service.autofill.AutofillFieldClassificationService#onBind(android.content.Intent) parameter #0:
+    
+MissingNullability: android.service.autofill.CompositeUserData#getCategoryIds():
+    
+MissingNullability: android.service.autofill.CompositeUserData#getDefaultFieldClassificationArgs():
+    
+MissingNullability: android.service.autofill.CompositeUserData#getFieldClassificationAlgorithms():
+    
+MissingNullability: android.service.autofill.CompositeUserData#getFieldClassificationArgs():
+    
+MissingNullability: android.service.autofill.CompositeUserData#getValues():
+    
+MissingNullability: android.service.autofill.CompositeUserData#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.service.autofill.UserData#getFieldClassificationAlgorithms():
+    
+MissingNullability: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
+    
+MissingNullability: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #1:
+    
+MissingNullability: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #2:
+    
+MissingNullability: android.service.autofill.augmented.AugmentedAutofillService#onUnbind(android.content.Intent) parameter #0:
+    
+MissingNullability: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
+    
+MissingNullability: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #1:
+    
+MissingNullability: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #2:
+    
+MissingNullability: android.service.notification.Adjustment#Adjustment(String, String, android.os.Bundle, CharSequence, int) parameter #0:
+    
+MissingNullability: android.service.notification.Adjustment#Adjustment(String, String, android.os.Bundle, CharSequence, int) parameter #1:
+    
+MissingNullability: android.service.notification.Adjustment#Adjustment(String, String, android.os.Bundle, CharSequence, int) parameter #2:
+    
+MissingNullability: android.service.notification.Adjustment#Adjustment(String, String, android.os.Bundle, CharSequence, int) parameter #3:
+    
+MissingNullability: android.service.notification.Adjustment#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context) parameter #0:
+    
+MissingNullability: android.service.notification.NotificationStats#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.service.notification.SnoozeCriterion#SnoozeCriterion(String, CharSequence, CharSequence) parameter #0:
+    
+MissingNullability: android.service.notification.SnoozeCriterion#SnoozeCriterion(String, CharSequence, CharSequence) parameter #1:
+    
+MissingNullability: android.service.notification.SnoozeCriterion#SnoozeCriterion(String, CharSequence, CharSequence) parameter #2:
+    
+MissingNullability: android.service.notification.SnoozeCriterion#SnoozeCriterion(android.os.Parcel) parameter #0:
+    
+MissingNullability: android.service.notification.SnoozeCriterion#getConfirmation():
+    
+MissingNullability: android.service.notification.SnoozeCriterion#getExplanation():
+    
+MissingNullability: android.service.notification.SnoozeCriterion#getId():
+    
+MissingNullability: android.service.notification.SnoozeCriterion#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.telecom.Call.Details#getTelecomCallId():
+    
+MissingNullability: android.telecom.CallScreeningService.CallResponse.Builder#setShouldScreenCallFurther(boolean):
+    
+MissingNullability: android.telecom.Conference#getPrimaryConnection():
+    
+MissingNullability: android.telecom.PhoneAccountSuggestionService#onBind(android.content.Intent):
+    
+MissingNullability: android.telecom.PhoneAccountSuggestionService#onBind(android.content.Intent) parameter #0:
+    
+MissingNullability: android.telephony.DataSpecificRegistrationInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.telephony.LteVopsSupportInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.telephony.NetworkRegistrationInfo#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.telephony.ServiceState#addNetworkRegistrationInfo(android.telephony.NetworkRegistrationInfo) parameter #0:
+    
+MissingNullability: android.telephony.ServiceState#setCellBandwidths(int[]) parameter #0:
+    
+MissingNullability: android.telephony.SmsManager#checkSmsShortCodeDestination(String, String) parameter #0:
+    
+MissingNullability: android.telephony.SmsManager#checkSmsShortCodeDestination(String, String) parameter #1:
+    
+MissingNullability: android.telephony.TelephonyManager#checkCarrierPrivilegesForPackage(String) parameter #0:
+    
+MissingNullability: android.telephony.TelephonyManager#getLine1AlphaTag():
+    
+MissingNullability: android.telephony.TelephonyManager#getRadioHalVersion():
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #0:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #1:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #2:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #3:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #4:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #5:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String) parameter #6:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #0:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #1:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #2:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #3:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #4:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #5:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #6:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #7:
+    
+MissingNullability: android.telephony.TelephonyManager#setCarrierTestOverride(String, String, String, String, String, String, String, String, String) parameter #8:
+    
+MissingNullability: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String):
+    
+MissingNullability: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String) parameter #0:
+    
+MissingNullability: android.telephony.mbms.FileInfo#FileInfo(android.net.Uri, String) parameter #0:
+    
+MissingNullability: android.telephony.mbms.FileInfo#FileInfo(android.net.Uri, String) parameter #1:
+    
+MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #0:
+    
+MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #1:
+    
+MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #2:
+    
+MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #3:
+    
+MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #4:
+    
+MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #5:
+    
+MissingNullability: android.telephony.mbms.FileServiceInfo#FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>) parameter #6:
+    
+MissingNullability: android.telephony.mbms.StreamingServiceInfo#StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date) parameter #0:
+    
+MissingNullability: android.telephony.mbms.StreamingServiceInfo#StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date) parameter #1:
+    
+MissingNullability: android.telephony.mbms.StreamingServiceInfo#StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date) parameter #2:
+    
+MissingNullability: android.telephony.mbms.StreamingServiceInfo#StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date) parameter #3:
+    
+MissingNullability: android.telephony.mbms.StreamingServiceInfo#StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date) parameter #4:
+    
+MissingNullability: android.telephony.mbms.StreamingServiceInfo#StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date) parameter #5:
+    
+MissingNullability: android.telephony.mbms.UriPathPair#getContentUri():
+    
+MissingNullability: android.telephony.mbms.UriPathPair#getFilePathUri():
+    
+MissingNullability: android.telephony.mbms.UriPathPair#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#asBinder():
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#cancelDownload(android.telephony.mbms.DownloadRequest) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#download(android.telephony.mbms.DownloadRequest) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#onTransact(int, android.os.Parcel, android.os.Parcel, int) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#onTransact(int, android.os.Parcel, android.os.Parcel, int) parameter #2:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#removeProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#removeProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#removeStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#removeStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#requestDownloadState(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#requestDownloadState(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#requestUpdateFileServices(int, java.util.List<java.lang.String>) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#resetDownloadKnowledge(android.telephony.mbms.DownloadRequest) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsDownloadServiceBase#setTempFileRootDirectory(int, String) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#onBind(android.content.Intent):
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#onBind(android.content.Intent) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#asBinder():
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#getPlaybackUri(int, String) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#onTransact(int, android.os.Parcel, android.os.Parcel, int) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#onTransact(int, android.os.Parcel, android.os.Parcel, int) parameter #2:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#requestUpdateStreamingServices(int, java.util.List<java.lang.String>) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#startStreaming(int, String, android.telephony.mbms.StreamingServiceCallback) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#startStreaming(int, String, android.telephony.mbms.StreamingServiceCallback) parameter #2:
+    
+MissingNullability: android.telephony.mbms.vendor.MbmsStreamingServiceBase#stopStreaming(int, String) parameter #1:
+    
+MissingNullability: android.telephony.mbms.vendor.VendorUtils#getAppReceiverFromPackageName(android.content.Context, String):
+    
+MissingNullability: android.telephony.mbms.vendor.VendorUtils#getAppReceiverFromPackageName(android.content.Context, String) parameter #0:
+    
+MissingNullability: android.telephony.mbms.vendor.VendorUtils#getAppReceiverFromPackageName(android.content.Context, String) parameter #1:
+    
+MissingNullability: android.text.Selection.MemoryTextWatcher#afterTextChanged(android.text.Editable) parameter #0:
+    
+MissingNullability: android.text.Selection.MemoryTextWatcher#beforeTextChanged(CharSequence, int, int, int) parameter #0:
+    
+MissingNullability: android.text.Selection.MemoryTextWatcher#onTextChanged(CharSequence, int, int, int) parameter #0:
+    
+MissingNullability: android.transition.TransitionManager#getTransition(android.transition.Scene):
+    
+MissingNullability: android.transition.TransitionManager#getTransition(android.transition.Scene) parameter #0:
+    
+MissingNullability: android.util.FeatureFlagUtils#getAllFeatureFlags():
+    
+MissingNullability: android.util.FeatureFlagUtils#isEnabled(android.content.Context, String) parameter #0:
+    
+MissingNullability: android.util.FeatureFlagUtils#isEnabled(android.content.Context, String) parameter #1:
+    
+MissingNullability: android.util.FeatureFlagUtils#setEnabled(android.content.Context, String, boolean) parameter #0:
+    
+MissingNullability: android.util.FeatureFlagUtils#setEnabled(android.content.Context, String, boolean) parameter #1:
+    
+MissingNullability: android.util.TimeUtils#formatDuration(long):
+    
+MissingNullability: android.util.proto.EncodedBuffer#dumpBuffers(String) parameter #0:
+    
+MissingNullability: android.util.proto.EncodedBuffer#dumpByteString(String, String, byte[]) parameter #0:
+    
+MissingNullability: android.util.proto.EncodedBuffer#dumpByteString(String, String, byte[]) parameter #1:
+    
+MissingNullability: android.util.proto.EncodedBuffer#dumpByteString(String, String, byte[]) parameter #2:
+    
+MissingNullability: android.util.proto.EncodedBuffer#getBytes(int):
+    
+MissingNullability: android.util.proto.EncodedBuffer#getDebugString():
+    
+MissingNullability: android.util.proto.EncodedBuffer#writeRawBuffer(byte[]) parameter #0:
+    
+MissingNullability: android.util.proto.EncodedBuffer#writeRawBuffer(byte[], int, int) parameter #0:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#ProtoOutputStream(java.io.FileDescriptor) parameter #0:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#ProtoOutputStream(java.io.OutputStream) parameter #0:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#dump(String) parameter #0:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#getBytes():
+    
+MissingNullability: android.util.proto.ProtoOutputStream#write(long, String) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#write(long, byte[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writeBytes(long, byte[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writeObject(long, byte[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedBool(long, boolean[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedDouble(long, double[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedEnum(long, int[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedFixed32(long, int[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedFixed64(long, long[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedFloat(long, float[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedInt32(long, int[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedInt64(long, long[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedSFixed32(long, int[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedSFixed64(long, long[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedSInt32(long, int[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedSInt64(long, long[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedUInt32(long, int[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writePackedUInt64(long, long[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writeRepeatedBytes(long, byte[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writeRepeatedObject(long, byte[]) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writeRepeatedString(long, String) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoOutputStream#writeString(long, String) parameter #1:
+    
+MissingNullability: android.util.proto.ProtoParseException#ProtoParseException(String) parameter #0:
+    
+MissingNullability: android.util.proto.ProtoStream#FIELD_TYPE_NAMES:
+    
+MissingNullability: android.util.proto.ProtoStream#getFieldCountString(long):
+    
+MissingNullability: android.util.proto.ProtoStream#getFieldIdString(long):
+    
+MissingNullability: android.util.proto.ProtoStream#getFieldTypeString(long):
+    
+MissingNullability: android.util.proto.ProtoStream#getWireTypeString(int):
+    
+MissingNullability: android.util.proto.ProtoStream#token2String(long):
+    
+MissingNullability: android.util.proto.WireTypeMismatchException#WireTypeMismatchException(String) parameter #0:
+    
+MissingNullability: android.view.Choreographer#postCallback(int, Runnable, Object) parameter #1:
+    
+MissingNullability: android.view.Choreographer#postCallback(int, Runnable, Object) parameter #2:
+    
+MissingNullability: android.view.Choreographer#postCallbackDelayed(int, Runnable, Object, long) parameter #1:
+    
+MissingNullability: android.view.Choreographer#postCallbackDelayed(int, Runnable, Object, long) parameter #2:
+    
+MissingNullability: android.view.Choreographer#removeCallbacks(int, Runnable, Object) parameter #1:
+    
+MissingNullability: android.view.Choreographer#removeCallbacks(int, Runnable, Object) parameter #2:
+    
+MissingNullability: android.view.FocusFinder#sort(android.view.View[], int, int, android.view.ViewGroup, boolean) parameter #0:
+    
+MissingNullability: android.view.FocusFinder#sort(android.view.View[], int, int, android.view.ViewGroup, boolean) parameter #3:
+    
+MissingNullability: android.view.KeyEvent#actionToString(int):
+    
+MissingNullability: android.view.View#getTooltipView():
+    
+MissingNullability: android.view.View#isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable) parameter #0:
+    
+MissingNullability: android.view.View#isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable) parameter #1:
+    
+MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.concurrent.Callable<java.io.OutputStream>) parameter #0:
+    
+MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.concurrent.Callable<java.io.OutputStream>) parameter #1:
+    
+MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.concurrent.Callable<java.io.OutputStream>) parameter #2:
+    
+MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.function.Function<android.graphics.Picture,java.lang.Boolean>) parameter #0:
+    
+MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.function.Function<android.graphics.Picture,java.lang.Boolean>) parameter #1:
+    
+MissingNullability: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.function.Function<android.graphics.Picture,java.lang.Boolean>) parameter #2:
+    
+MissingNullability: android.view.WindowManager.LayoutParams#accessibilityTitle:
+    
+MissingNullability: android.view.WindowlessViewRoot#WindowlessViewRoot(android.content.Context, android.view.Display, android.view.SurfaceControl) parameter #0:
+    
+MissingNullability: android.view.WindowlessViewRoot#WindowlessViewRoot(android.content.Context, android.view.Display, android.view.SurfaceControl) parameter #1:
+    
+MissingNullability: android.view.WindowlessViewRoot#WindowlessViewRoot(android.content.Context, android.view.Display, android.view.SurfaceControl) parameter #2:
+    
+MissingNullability: android.view.WindowlessViewRoot#addView(android.view.View, android.view.WindowManager.LayoutParams) parameter #0:
+    
+MissingNullability: android.view.WindowlessViewRoot#addView(android.view.View, android.view.WindowManager.LayoutParams) parameter #1:
+    
+MissingNullability: android.view.WindowlessViewRoot#relayout(android.view.WindowManager.LayoutParams) parameter #0:
+    
+MissingNullability: android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener#onAccessibilityServicesStateChanged(android.view.accessibility.AccessibilityManager) parameter #0:
+    
+MissingNullability: android.view.accessibility.AccessibilityNodeInfo#setNumInstancesInUseCounter(java.util.concurrent.atomic.AtomicInteger) parameter #0:
+    
+MissingNullability: android.view.accessibility.AccessibilityNodeInfo#writeToParcelNoRecycle(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.view.accessibility.AccessibilityWindowInfo#setNumInstancesInUseCounter(java.util.concurrent.atomic.AtomicInteger) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ContentCaptureEvent#writeToParcel(android.os.Parcel, int) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#asyncNewChild(int):
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getAutofillId():
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getExtras():
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getHint():
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getNode():
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getTempRect():
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#getText():
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#newChild(int):
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#newHtmlInfoBuilder(String):
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#newHtmlInfoBuilder(String) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillHints(String[]) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillId(android.view.autofill.AutofillId) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillId(android.view.autofill.AutofillId, int) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillOptions(CharSequence[]) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setAutofillValue(android.view.autofill.AutofillValue) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setClassName(String) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setContentDescription(CharSequence) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setHint(CharSequence) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setHintIdEntry(String) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setHtmlInfo(android.view.ViewStructure.HtmlInfo) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setId(int, String, String, String) parameter #1:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setId(int, String, String, String) parameter #2:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setId(int, String, String, String) parameter #3:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setLocaleList(android.os.LocaleList) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setText(CharSequence) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setText(CharSequence, int, int) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setTextLines(int[], int[]) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setTextLines(int[], int[]) parameter #1:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setTransformation(android.graphics.Matrix) parameter #0:
+    
+MissingNullability: android.view.contentcapture.ViewNode.ViewStructureImpl#setWebDomain(String) parameter #0:
+    
+MissingNullability: android.widget.CalendarView#getBoundsForDate(long, android.graphics.Rect) parameter #1:
+    
+MissingNullability: android.widget.ImageView#isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable) parameter #0:
+    
+MissingNullability: android.widget.ImageView#isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable) parameter #1:
+    
+MissingNullability: android.widget.Magnifier#getMagnifierDefaultSize():
+    
+MissingNullability: android.widget.Magnifier#setOnOperationCompleteCallback(android.widget.Magnifier.Callback) parameter #0:
+    
+MissingNullability: android.widget.NumberPicker#getDisplayedValueForCurrentSelection():
+    
+MissingNullability: android.widget.PopupMenu#getMenuListView():
+    
+MissingNullability: android.widget.TimePicker#getAmView():
+    
+MissingNullability: android.widget.TimePicker#getHourView():
+    
+MissingNullability: android.widget.TimePicker#getMinuteView():
+    
+MissingNullability: android.widget.TimePicker#getPmView():
+    
+
+
+MutableBareField: android.content.AutofillOptions#appDisabledExpiration:
+    
+MutableBareField: android.content.AutofillOptions#augmentedAutofillEnabled:
+    
+MutableBareField: android.content.AutofillOptions#disabledActivities:
+    
+MutableBareField: android.content.AutofillOptions#whitelistedActivitiesForAugmentedAutofill:
+    
+MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#cache:
+    
+MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#dbName:
+    
+MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#dbSize:
+    
+MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#lookaside:
+    
+MutableBareField: android.database.sqlite.SQLiteDebug.DbStats#pageSize:
+    
+MutableBareField: android.database.sqlite.SQLiteDebug.PagerStats#dbStats:
+    
+MutableBareField: android.database.sqlite.SQLiteDebug.PagerStats#largestMemAlloc:
+    
+MutableBareField: android.database.sqlite.SQLiteDebug.PagerStats#memoryUsed:
+    
+MutableBareField: android.database.sqlite.SQLiteDebug.PagerStats#pageCacheOverflow:
+    
+MutableBareField: android.os.StrictMode.ViolationInfo#broadcastIntentAction:
+    
+MutableBareField: android.os.StrictMode.ViolationInfo#durationMillis:
+    
+MutableBareField: android.os.StrictMode.ViolationInfo#numAnimationsRunning:
+    
+MutableBareField: android.os.StrictMode.ViolationInfo#numInstances:
+    
+MutableBareField: android.os.StrictMode.ViolationInfo#tags:
+    
+MutableBareField: android.os.StrictMode.ViolationInfo#violationNumThisLoop:
+    
+MutableBareField: android.os.StrictMode.ViolationInfo#violationUptimeMillis:
+    
+
+
+NoByteOrShort: android.media.audiofx.AudioEffect#byteArrayToShort(byte[]):
+    
+NoByteOrShort: android.media.audiofx.AudioEffect#setParameter(int, short) parameter #1:
+    
+NoByteOrShort: android.media.audiofx.AudioEffect#shortToByteArray(short) parameter #0:
+    
+NoByteOrShort: android.os.HwBlob#getInt16(long):
+    
+NoByteOrShort: android.os.HwBlob#getInt8(long):
+    
+NoByteOrShort: android.os.HwBlob#putInt16(long, short) parameter #1:
+    
+NoByteOrShort: android.os.HwBlob#putInt8(long, byte) parameter #1:
+    
+NoByteOrShort: android.os.HwParcel#readInt16():
+    
+NoByteOrShort: android.os.HwParcel#readInt8():
+    
+NoByteOrShort: android.os.HwParcel#writeInt16(short) parameter #0:
+    
+NoByteOrShort: android.os.HwParcel#writeInt8(byte) parameter #0:
+    
+NoByteOrShort: android.util.proto.EncodedBuffer#readRawByte():
+    
+NoByteOrShort: android.util.proto.EncodedBuffer#writeRawByte(byte) parameter #0:
+    
+
+
+NoClone: android.net.util.SocketUtils#bindSocketToInterface(java.io.FileDescriptor, String) parameter #0:
+    
+NoClone: android.net.util.SocketUtils#closeSocket(java.io.FileDescriptor) parameter #0:
+    
+NoClone: android.os.NativeHandle#NativeHandle(java.io.FileDescriptor, boolean) parameter #0:
+    
+NoClone: android.os.NativeHandle#getFileDescriptor():
+    
+NoClone: android.os.ParcelFileDescriptor#getFile(java.io.FileDescriptor) parameter #0:
+    
+NoClone: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
+    
+NoClone: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
+    
+NoClone: android.util.proto.ProtoOutputStream#ProtoOutputStream(java.io.FileDescriptor) parameter #0:
+    
+
+
+NotCloseable: android.app.ActivityView:
+    
+NotCloseable: android.app.prediction.AppPredictor:
+    
+NotCloseable: android.os.HwParcel:
+    
+
+
+OnNameExpected: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.PrintWriter, String[]):
+    
+OnNameExpected: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
+    
+OnNameExpected: android.service.notification.ConditionProviderService#isBound():
+    
+OnNameExpected: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context):
+    
+OnNameExpected: android.service.quicksettings.TileService#isQuickSettingsSupported():
+    
+OnNameExpected: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#dispose(int):
+    
+OnNameExpected: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int):
+    
+OnNameExpected: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#startGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>, android.telephony.mbms.GroupCallCallback):
+    
+OnNameExpected: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#stopGroupCall(int, long):
+    
+OnNameExpected: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#updateGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>):
+    
+
+
+PackageLayering: android.util.FeatureFlagUtils:
+    
+
+
+ParcelConstructor: android.os.IncidentManager.IncidentReport#IncidentReport(android.os.Parcel):
+    
+ParcelConstructor: android.os.IncidentReportArgs#IncidentReportArgs(android.os.Parcel):
+    
+ParcelConstructor: android.os.StrictMode.ViolationInfo#ViolationInfo(android.os.Parcel):
+    
+ParcelConstructor: android.os.VibrationEffect.OneShot#OneShot(android.os.Parcel):
+    
+ParcelConstructor: android.os.VibrationEffect.Prebaked#Prebaked(android.os.Parcel):
+    
+ParcelConstructor: android.os.VibrationEffect.Waveform#Waveform(android.os.Parcel):
+    
+ParcelConstructor: android.os.health.HealthStatsParceler#HealthStatsParceler(android.os.Parcel):
+    
+ParcelConstructor: android.service.notification.SnoozeCriterion#SnoozeCriterion(android.os.Parcel):
+    
+
+
+ParcelCreator: android.app.WindowConfiguration:
+    
+ParcelCreator: android.net.metrics.ApfProgramEvent:
+    
+ParcelCreator: android.net.metrics.ApfStats:
+    
+ParcelCreator: android.net.metrics.DhcpClientEvent:
+    
+ParcelCreator: android.net.metrics.DhcpErrorEvent:
+    
+ParcelCreator: android.net.metrics.IpConnectivityLog.Event:
+    
+ParcelCreator: android.net.metrics.IpManagerEvent:
+    
+ParcelCreator: android.net.metrics.IpReachabilityEvent:
+    
+ParcelCreator: android.net.metrics.NetworkEvent:
+    
+ParcelCreator: android.net.metrics.RaEvent:
+    
+ParcelCreator: android.net.metrics.ValidationProbeEvent:
+    
+ParcelCreator: android.os.VibrationEffect.OneShot:
+    
+ParcelCreator: android.os.VibrationEffect.Prebaked:
+    
+ParcelCreator: android.os.VibrationEffect.Waveform:
+    
+ParcelCreator: android.service.autofill.InternalOnClickAction:
+    
+ParcelCreator: android.service.autofill.InternalSanitizer:
+    
+ParcelCreator: android.service.autofill.InternalTransformation:
+    
+ParcelCreator: android.service.autofill.InternalValidator:
+    
+
+
+ParcelNotFinal: android.app.WindowConfiguration:
+    
+ParcelNotFinal: android.net.metrics.IpConnectivityLog.Event:
+    
+ParcelNotFinal: android.os.IncidentManager.IncidentReport:
+    
+ParcelNotFinal: android.os.VibrationEffect.OneShot:
+    
+ParcelNotFinal: android.os.VibrationEffect.Prebaked:
+    
+ParcelNotFinal: android.os.VibrationEffect.Waveform:
+    
+ParcelNotFinal: android.os.health.HealthStatsParceler:
+    
+ParcelNotFinal: android.service.autofill.InternalOnClickAction:
+    
+ParcelNotFinal: android.service.autofill.InternalSanitizer:
+    
+ParcelNotFinal: android.service.autofill.InternalTransformation:
+    
+ParcelNotFinal: android.service.autofill.InternalValidator:
+    
+
+
+ProtectedMember: android.app.ActivityView#onVisibilityChanged(android.view.View, int):
+    
+ProtectedMember: android.app.AppDetailsActivity#onCreate(android.os.Bundle):
+    
+ProtectedMember: android.os.VibrationEffect#scale(int, float, int):
+    
+ProtectedMember: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
+    
+ProtectedMember: android.service.autofill.augmented.AugmentedAutofillService#dump(java.io.PrintWriter, String[]):
+    
+ProtectedMember: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
+    
+ProtectedMember: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context):
+    
+ProtectedMember: android.util.proto.ProtoStream#FIELD_TYPE_NAMES:
+    
+ProtectedMember: android.view.View#resetResolvedDrawables():
+    
+ProtectedMember: android.view.ViewGroup#resetResolvedDrawables():
+    
+
+
+RawAidl: android.telephony.mbms.vendor.MbmsDownloadServiceBase:
+    
+RawAidl: android.telephony.mbms.vendor.MbmsStreamingServiceBase:
+    
+
+
+RethrowRemoteException: android.app.ActivityManager#resumeAppSwitches():
+    
+RethrowRemoteException: android.os.HwBinder#getService(String, String):
+    
+RethrowRemoteException: android.os.HwBinder#getService(String, String, boolean):
+    
+RethrowRemoteException: android.os.HwBinder#onTransact(int, android.os.HwParcel, android.os.HwParcel, int):
+    
+RethrowRemoteException: android.os.HwBinder#registerService(String):
+    
+RethrowRemoteException: android.os.HwBinder#transact(int, android.os.HwParcel, android.os.HwParcel, int):
+    
+RethrowRemoteException: android.os.IHwBinder#transact(int, android.os.HwParcel, android.os.HwParcel, int):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#cancelDownload(android.telephony.mbms.DownloadRequest):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#dispose(int):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#download(android.telephony.mbms.DownloadRequest):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#listPendingDownloads(int):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#onTransact(int, android.os.Parcel, android.os.Parcel, int):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#removeProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#removeStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#requestDownloadState(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#requestUpdateFileServices(int, java.util.List<java.lang.String>):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#resetDownloadKnowledge(android.telephony.mbms.DownloadRequest):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsDownloadServiceBase#setTempFileRootDirectory(int, String):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#dispose(int):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsGroupCallServiceBase#initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#dispose(int):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#getPlaybackUri(int, String):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#onTransact(int, android.os.Parcel, android.os.Parcel, int):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#requestUpdateStreamingServices(int, java.util.List<java.lang.String>):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#startStreaming(int, String, android.telephony.mbms.StreamingServiceCallback):
+    
+RethrowRemoteException: android.telephony.mbms.vendor.MbmsStreamingServiceBase#stopStreaming(int, String):
+    
+
+
+SamShouldBeLast: android.app.ActivityManager#addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int):
+    
+SamShouldBeLast: android.app.role.RoleManager#addOnRoleHoldersChangedListenerAsUser(java.util.concurrent.Executor, android.app.role.OnRoleHoldersChangedListener, android.os.UserHandle):
+    
+SamShouldBeLast: android.app.role.RoleManager#removeOnRoleHoldersChangedListenerAsUser(android.app.role.OnRoleHoldersChangedListener, android.os.UserHandle):
+    
+SamShouldBeLast: android.database.sqlite.SQLiteDebug#dump(android.util.Printer, String[]):
+    
+SamShouldBeLast: android.database.sqlite.SQLiteDirectCursorDriver#query(android.database.sqlite.SQLiteDatabase.CursorFactory, String[]):
+    
+SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(android.location.LocationRequest, java.util.concurrent.Executor, android.location.LocationListener):
+    
+SamShouldBeLast: android.os.BugreportManager#startBugreport(android.os.ParcelFileDescriptor, android.os.ParcelFileDescriptor, android.os.BugreportParams, java.util.concurrent.Executor, android.os.BugreportManager.BugreportCallback):
+    
+SamShouldBeLast: android.os.IHwBinder#linkToDeath(android.os.IHwBinder.DeathRecipient, long):
+    
+SamShouldBeLast: android.os.StrictMode.ViolationInfo#dump(android.util.Printer, String):
+    
+SamShouldBeLast: android.permission.PermissionControllerManager#getAppPermissions(String, android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, android.os.Handler):
+    
+SamShouldBeLast: android.permission.PermissionControllerManager#revokeRuntimePermissions(java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, java.util.concurrent.Executor, android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback):
+    
+SamShouldBeLast: android.service.autofill.CharSequenceTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int):
+    
+SamShouldBeLast: android.service.autofill.DateTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int):
+    
+SamShouldBeLast: android.service.autofill.ImageTransformation#apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int):
+    
+SamShouldBeLast: android.service.autofill.InternalTransformation#batchApply(android.service.autofill.ValueFinder, android.widget.RemoteViews, java.util.ArrayList<android.util.Pair<java.lang.Integer,android.service.autofill.InternalTransformation>>):
+    
+SamShouldBeLast: android.view.Choreographer#postCallback(int, Runnable, Object):
+    
+SamShouldBeLast: android.view.Choreographer#postCallbackDelayed(int, Runnable, Object, long):
+    
+SamShouldBeLast: android.view.Choreographer#removeCallbacks(int, Runnable, Object):
+    
+SamShouldBeLast: android.view.ViewDebug#startRenderingCommandsCapture(android.view.View, java.util.concurrent.Executor, java.util.function.Function<android.graphics.Picture,java.lang.Boolean>):
+    
+SamShouldBeLast: android.view.accessibility.AccessibilityManager#addAccessibilityServicesStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener, android.os.Handler):
+    
+
+
+ServiceName: android.Manifest.permission#BIND_CELL_BROADCAST_SERVICE:
+    
+ServiceName: android.app.AppOpsManager#OPSTR_BIND_ACCESSIBILITY_SERVICE:
+    
+ServiceName: android.provider.Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE:
+    
+ServiceName: android.provider.Settings.Secure#AUTOFILL_SERVICE:
+    
+ServiceName: android.provider.Settings.Secure#VOICE_INTERACTION_SERVICE:
+    
+
+
+SetterReturnsThis: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyFocusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener):
+    
+SetterReturnsThis: android.media.audiopolicy.AudioPolicy.Builder#setAudioPolicyStatusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener):
+    
+
+
+StaticUtils: android.os.health.HealthKeys:
+    
+StaticUtils: android.service.autofill.InternalTransformation:
+    
+StaticUtils: android.telephony.mbms.vendor.VendorUtils:
+    
+StaticUtils: android.util.FeatureFlagUtils:
+    
+StaticUtils: android.util.proto.ProtoStream:
+    
+
+
+StreamFiles: android.os.Environment#buildPath(java.io.File, java.lang.String...):
+    
+StreamFiles: android.os.FileUtils#contains(java.io.File, java.io.File):
+    
+StreamFiles: android.provider.MediaStore#scanFile(android.content.Context, java.io.File):
+    
+StreamFiles: android.provider.MediaStore#scanFileFromShell(android.content.Context, java.io.File):
+    
+StreamFiles: android.provider.MediaStore#scanVolume(android.content.Context, java.io.File):
+    
+
+
+UseParcelFileDescriptor: android.util.proto.ProtoOutputStream#ProtoOutputStream(java.io.FileDescriptor) parameter #0:
+    
+
+
+UserHandle: android.app.admin.DevicePolicyManager#getOwnerInstalledCaCerts(android.os.UserHandle):
+    
+UserHandle: android.app.role.RoleManager#addOnRoleHoldersChangedListenerAsUser(java.util.concurrent.Executor, android.app.role.OnRoleHoldersChangedListener, android.os.UserHandle):
+    
+UserHandle: android.app.role.RoleManager#addRoleHolderAsUser(String, String, int, android.os.UserHandle, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Boolean>):
+    
+UserHandle: android.app.role.RoleManager#clearRoleHoldersAsUser(String, int, android.os.UserHandle, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Boolean>):
+    
+UserHandle: android.app.role.RoleManager#getRoleHoldersAsUser(String, android.os.UserHandle):
+    
+UserHandle: android.app.role.RoleManager#removeOnRoleHoldersChangedListenerAsUser(android.app.role.OnRoleHoldersChangedListener, android.os.UserHandle):
+    
+UserHandle: android.app.role.RoleManager#removeRoleHolderAsUser(String, String, int, android.os.UserHandle, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Boolean>):
+    
+UserHandle: android.content.pm.PackageManager#getInstallReason(String, android.os.UserHandle):
+    
+UserHandle: android.content.pm.PackageManager#getPermissionFlags(String, String, android.os.UserHandle):
+    
+UserHandle: android.content.pm.PackageManager#grantRuntimePermission(String, String, android.os.UserHandle):
+    
+UserHandle: android.content.pm.PackageManager#revokeRuntimePermission(String, String, android.os.UserHandle):
+    
+UserHandle: android.content.pm.PackageManager#updatePermissionFlags(String, String, int, int, android.os.UserHandle):
+    
+UserHandle: android.location.LocationManager#setLocationEnabledForUser(boolean, android.os.UserHandle):
+    
+UserHandle: android.permission.PermissionControllerManager#applyStagedRuntimePermissionBackup(String, android.os.UserHandle, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Boolean>):
+    
+UserHandle: android.permission.PermissionControllerManager#getRuntimePermissionBackup(android.os.UserHandle, java.util.concurrent.Executor, java.util.function.Consumer<byte[]>):
+    
+UserHandle: android.permission.PermissionControllerManager#stageAndApplyRuntimePermissionsBackup(byte[], android.os.UserHandle):
+    
+
+
+UserHandleName: android.app.ActivityView#startActivity(android.content.Intent, android.os.UserHandle):
+    
+UserHandleName: android.content.AutofillOptions:
+    
+UserHandleName: android.content.ContentCaptureOptions:
+    
+UserHandleName: android.os.IncidentReportArgs:
+    
+UserHandleName: android.provider.MediaStore#deleteContributedMedia(android.content.Context, String, android.os.UserHandle):
+    
+UserHandleName: android.provider.MediaStore#getContributedMediaSize(android.content.Context, String, android.os.UserHandle):
+    
+
+
+VisiblySynchronized: PsiClassObjectAccessExpression:
+    
+VisiblySynchronized: PsiThisExpression:
+    
+VisiblySynchronized: android.app.ActivityManager#addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int):
+    
+VisiblySynchronized: android.app.ActivityManager#removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener):
+    
+VisiblySynchronized: android.content.ContentProviderClient#setDetectNotResponding(long):
+    
+VisiblySynchronized: android.content.res.AssetManager#getApkPaths():
+    
+VisiblySynchronized: android.content.res.AssetManager#getLastResourceResolution():
+    
+VisiblySynchronized: android.content.res.AssetManager#getOverlayablesToString(String):
+    
+VisiblySynchronized: android.content.res.AssetManager#setResourceResolutionLoggingEnabled(boolean):
+    
+VisiblySynchronized: android.os.MessageQueue#removeSyncBarrier(int):
+    
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
index 55dbc17..7e278e9 100644
--- a/cmds/content/src/com/android/commands/content/Content.java
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -508,7 +508,7 @@
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            provider.insert(resolveCallingPackage(), mUri, mContentValues);
+            provider.insert(resolveCallingPackage(), null, mUri, mContentValues);
         }
     }
 
@@ -522,7 +522,7 @@
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            provider.delete(resolveCallingPackage(), mUri, mWhere, null);
+            provider.delete(resolveCallingPackage(), null, mUri, mWhere, null);
         }
     }
 
@@ -557,7 +557,7 @@
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            Bundle result = provider.call(null, mUri.getAuthority(), mMethod, mArg, mExtras);
+            Bundle result = provider.call(null, null, mUri.getAuthority(), mMethod, mArg, mExtras);
             if (result != null) {
                 result.size(); // unpack
             }
@@ -584,7 +584,7 @@
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            try (ParcelFileDescriptor fd = provider.openFile(null, mUri, "r", null, null)) {
+            try (ParcelFileDescriptor fd = provider.openFile(null, null, mUri, "r", null, null)) {
                 FileUtils.copy(fd.getFileDescriptor(), FileDescriptor.out);
             }
         }
@@ -597,7 +597,7 @@
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            try (ParcelFileDescriptor fd = provider.openFile(null, mUri, "w", null, null)) {
+            try (ParcelFileDescriptor fd = provider.openFile(null, null, mUri, "w", null, null)) {
                 FileUtils.copy(FileDescriptor.in, fd.getFileDescriptor());
             }
         }
@@ -616,7 +616,7 @@
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            Cursor cursor = provider.query(resolveCallingPackage(), mUri, mProjection,
+            Cursor cursor = provider.query(resolveCallingPackage(), null, mUri, mProjection,
                     ContentResolver.createSqlQueryBundle(mWhere, null, mSortOrder), null);
             if (cursor == null) {
                 System.out.println("No result found.");
@@ -679,7 +679,7 @@
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            provider.update(resolveCallingPackage(), mUri, mContentValues, mWhere, null);
+            provider.update(resolveCallingPackage(), null, mUri, mContentValues, mWhere, null);
         }
     }
 
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 1572114..c9277a5 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -476,10 +476,28 @@
 // initialization only once in Section.cpp.
 map<log_id_t, log_time> LogSection::gLastLogsRetrieved;
 
-LogSection::LogSection(int id, log_id_t logID) : WorkerThreadSection(id), mLogID(logID) {
-    name = "logcat ";
-    name += android_log_id_to_name(logID);
-    switch (logID) {
+LogSection::LogSection(int id, const char* logID, ...) : WorkerThreadSection(id), mLogMode(logModeBase) {
+    name = "logcat -b ";
+    name += logID;
+
+    va_list args;
+    va_start(args, logID);
+    mLogID = android_name_to_log_id(logID);
+    while(true) {
+        const char* arg = va_arg(args, const char*);
+        if (arg == NULL) {
+            break;
+        }
+        if (!strcmp(arg, "-L")) {
+          // Read from last logcat buffer
+          mLogMode = mLogMode | ANDROID_LOG_PSTORE;
+        }
+        name += " ";
+        name += arg;
+    }
+    va_end(args);
+
+    switch (mLogID) {
         case LOG_ID_EVENTS:
         case LOG_ID_STATS:
         case LOG_ID_SECURITY:
@@ -512,9 +530,8 @@
     // Open log buffer and getting logs since last retrieved time if any.
     unique_ptr<logger_list, void (*)(logger_list*)> loggers(
             gLastLogsRetrieved.find(mLogID) == gLastLogsRetrieved.end()
-                    ? android_logger_list_alloc(ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, 0)
-                    : android_logger_list_alloc_time(ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
-                                                     gLastLogsRetrieved[mLogID], 0),
+                    ? android_logger_list_alloc(mLogMode, 0, 0)
+                    : android_logger_list_alloc_time(mLogMode, gLastLogsRetrieved[mLogID], 0),
             android_logger_list_free);
 
     if (android_logger_open(loggers.get(), mLogID) == NULL) {
@@ -546,16 +563,16 @@
             ;
             android_log_list_element elem;
 
-            lastTimestamp.tv_sec = msg.entry_v1.sec;
-            lastTimestamp.tv_nsec = msg.entry_v1.nsec;
+            lastTimestamp.tv_sec = msg.entry.sec;
+            lastTimestamp.tv_nsec = msg.entry.nsec;
 
             // format a BinaryLogEntry
             uint64_t token = proto.start(LogProto::BINARY_LOGS);
-            proto.write(BinaryLogEntry::SEC, msg.entry_v1.sec);
-            proto.write(BinaryLogEntry::NANOSEC, msg.entry_v1.nsec);
-            proto.write(BinaryLogEntry::UID, (int)msg.entry_v4.uid);
-            proto.write(BinaryLogEntry::PID, msg.entry_v1.pid);
-            proto.write(BinaryLogEntry::TID, msg.entry_v1.tid);
+            proto.write(BinaryLogEntry::SEC, (int32_t)msg.entry.sec);
+            proto.write(BinaryLogEntry::NANOSEC, (int32_t)msg.entry.nsec);
+            proto.write(BinaryLogEntry::UID, (int)msg.entry.uid);
+            proto.write(BinaryLogEntry::PID, msg.entry.pid);
+            proto.write(BinaryLogEntry::TID, (int32_t)msg.entry.tid);
             proto.write(BinaryLogEntry::TAG_INDEX,
                         get4LE(reinterpret_cast<uint8_t const*>(msg.msg())));
             do {
@@ -603,7 +620,7 @@
             }
         } else {
             AndroidLogEntry entry;
-            err = android_log_processLogBuffer(&msg.entry_v1, &entry);
+            err = android_log_processLogBuffer(&msg.entry, &entry);
             if (err != NO_ERROR) {
                 ALOGW("[%s] fails to process to an entry.\n", this->name.string());
                 break;
diff --git a/cmds/incidentd/src/Section.h b/cmds/incidentd/src/Section.h
index c9b8056..fcf12f7 100644
--- a/cmds/incidentd/src/Section.h
+++ b/cmds/incidentd/src/Section.h
@@ -146,8 +146,11 @@
     // global last log retrieved timestamp for each log_id_t.
     static map<log_id_t, log_time> gLastLogsRetrieved;
 
+    // log mode: read only & non blocking.
+    const static int logModeBase = ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK;
+
 public:
-    LogSection(int id, log_id_t logID);
+    LogSection(int id, const char* logID, ...);
     virtual ~LogSection();
 
     virtual status_t BlockingCall(int pipeWriteFd) const;
@@ -155,6 +158,7 @@
 private:
     log_id_t mLogID;
     bool mBinary;
+    int mLogMode;
 };
 
 /**
diff --git a/cmds/statsd/benchmark/log_event_benchmark.cpp b/cmds/statsd/benchmark/log_event_benchmark.cpp
index 43addc2..2603469 100644
--- a/cmds/statsd/benchmark/log_event_benchmark.cpp
+++ b/cmds/statsd/benchmark/log_event_benchmark.cpp
@@ -54,9 +54,9 @@
     write4Bytes(99 /* a value to log*/, &buffer);
     buffer.push_back(EVENT_TYPE_LIST_STOP);
 
-    msg->entry_v1.len = buffer.size();
+    msg->entry.len = buffer.size();
     msg->entry.hdr_size = kLogMsgHeaderSize;
-    msg->entry_v1.sec = time(nullptr);
+    msg->entry.sec = time(nullptr);
     std::copy(buffer.begin(), buffer.end(), msg->buf + kLogMsgHeaderSize);
 }
 
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 6c3dff2..91cadc9 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -200,6 +200,10 @@
 }
 
 void StatsLogProcessor::OnLogEvent(LogEvent* event) {
+    OnLogEvent(event, getElapsedRealtimeNs());
+}
+
+void StatsLogProcessor::OnLogEvent(LogEvent* event, int64_t elapsedRealtimeNs) {
     std::lock_guard<std::mutex> lock(mMetricsMutex);
 
 #ifdef VERY_VERBOSE_PRINTING
@@ -207,9 +211,9 @@
         ALOGI("%s", event->ToString().c_str());
     }
 #endif
-    const int64_t currentTimestampNs = event->GetElapsedTimestampNs();
+    const int64_t eventElapsedTimeNs = event->GetElapsedTimestampNs();
 
-    resetIfConfigTtlExpiredLocked(currentTimestampNs);
+    resetIfConfigTtlExpiredLocked(eventElapsedTimeNs);
 
     StatsdStats::getInstance().noteAtomLogged(
         event->GetTagId(), event->GetElapsedTimestampNs() / NS_PER_SEC);
@@ -264,15 +268,16 @@
             uidsWithActiveConfigsChanged.insert(uid);
             StatsdStats::getInstance().noteActiveStatusChanged(pair.first, isCurActive);
         }
-        flushIfNecessaryLocked(event->GetElapsedTimestampNs(), pair.first, *(pair.second));
+        flushIfNecessaryLocked(pair.first, *(pair.second));
     }
 
+    // Don't use the event timestamp for the guardrail.
     for (int uid : uidsWithActiveConfigsChanged) {
         // Send broadcast so that receivers can pull data.
         auto lastBroadcastTime = mLastActivationBroadcastTimes.find(uid);
         if (lastBroadcastTime != mLastActivationBroadcastTimes.end()) {
-            if (currentTimestampNs - lastBroadcastTime->second <
-                    StatsdStats::kMinActivationBroadcastPeriodNs) {
+            if (elapsedRealtimeNs - lastBroadcastTime->second <
+                StatsdStats::kMinActivationBroadcastPeriodNs) {
                 StatsdStats::getInstance().noteActivationBroadcastGuardrailHit(uid);
                 VLOG("StatsD would've sent an activation broadcast but the rate limit stopped us.");
                 return;
@@ -282,13 +287,13 @@
         if (activeConfigs != activeConfigsPerUid.end()) {
             if (mSendActivationBroadcast(uid, activeConfigs->second)) {
                 VLOG("StatsD sent activation notice for uid %d", uid);
-                mLastActivationBroadcastTimes[uid] = currentTimestampNs;
+                mLastActivationBroadcastTimes[uid] = elapsedRealtimeNs;
             }
         } else {
             std::vector<int64_t> emptyActiveConfigs;
             if (mSendActivationBroadcast(uid, emptyActiveConfigs)) {
                 VLOG("StatsD sent EMPTY activation notice for uid %d", uid);
-                mLastActivationBroadcastTimes[uid] = currentTimestampNs;
+                mLastActivationBroadcastTimes[uid] = elapsedRealtimeNs;
             }
         }
     }
@@ -550,22 +555,23 @@
     }
 }
 
-void StatsLogProcessor::flushIfNecessaryLocked(
-    int64_t timestampNs, const ConfigKey& key, MetricsManager& metricsManager) {
+void StatsLogProcessor::flushIfNecessaryLocked(const ConfigKey& key,
+                                               MetricsManager& metricsManager) {
+    int64_t elapsedRealtimeNs = getElapsedRealtimeNs();
     auto lastCheckTime = mLastByteSizeTimes.find(key);
     if (lastCheckTime != mLastByteSizeTimes.end()) {
-        if (timestampNs - lastCheckTime->second < StatsdStats::kMinByteSizeCheckPeriodNs) {
+        if (elapsedRealtimeNs - lastCheckTime->second < StatsdStats::kMinByteSizeCheckPeriodNs) {
             return;
         }
     }
 
     // We suspect that the byteSize() computation is expensive, so we set a rate limit.
     size_t totalBytes = metricsManager.byteSize();
-    mLastByteSizeTimes[key] = timestampNs;
+    mLastByteSizeTimes[key] = elapsedRealtimeNs;
     bool requestDump = false;
-    if (totalBytes >
-        StatsdStats::kMaxMetricsBytesPerConfig) {  // Too late. We need to start clearing data.
-        metricsManager.dropData(timestampNs);
+    if (totalBytes > StatsdStats::kMaxMetricsBytesPerConfig) {
+        // Too late. We need to start clearing data.
+        metricsManager.dropData(elapsedRealtimeNs);
         StatsdStats::getInstance().noteDataDropped(key, totalBytes);
         VLOG("StatsD had to toss out metrics for %s", key.ToString().c_str());
     } else if ((totalBytes > StatsdStats::kBytesPerConfigTriggerGetData) ||
@@ -580,7 +586,8 @@
         // Send broadcast so that receivers can pull data.
         auto lastBroadcastTime = mLastBroadcastTimes.find(key);
         if (lastBroadcastTime != mLastBroadcastTimes.end()) {
-            if (timestampNs - lastBroadcastTime->second < StatsdStats::kMinBroadcastPeriodNs) {
+            if (elapsedRealtimeNs - lastBroadcastTime->second <
+                    StatsdStats::kMinBroadcastPeriodNs) {
                 VLOG("StatsD would've sent a broadcast but the rate limit stopped us.");
                 return;
             }
@@ -588,7 +595,7 @@
         if (mSendBroadcast(key)) {
             mOnDiskDataConfigs.erase(key);
             VLOG("StatsD triggered data fetch for %s", key.ToString().c_str());
-            mLastBroadcastTimes[key] = timestampNs;
+            mLastBroadcastTimes[key] = elapsedRealtimeNs;
             StatsdStats::getInstance().noteBroadcastSent(key);
         }
     }
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 8292a3a..17f2770 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -128,13 +128,13 @@
 
     std::unordered_map<ConfigKey, sp<MetricsManager>> mMetricsManagers;
 
-    std::unordered_map<ConfigKey, long> mLastBroadcastTimes;
+    std::unordered_map<ConfigKey, int64_t> mLastBroadcastTimes;
 
     // Last time we sent a broadcast to this uid that the active configs had changed.
-    std::unordered_map<int, long> mLastActivationBroadcastTimes;
+    std::unordered_map<int, int64_t> mLastActivationBroadcastTimes;
 
     // Tracks when we last checked the bytes consumed for each config key.
-    std::unordered_map<ConfigKey, long> mLastByteSizeTimes;
+    std::unordered_map<ConfigKey, int64_t> mLastByteSizeTimes;
 
     // Tracks which config keys has metric reports on disk
     std::set<ConfigKey> mOnDiskDataConfigs;
@@ -147,6 +147,8 @@
 
     sp<AlarmMonitor> mPeriodicAlarmMonitor;
 
+    void OnLogEvent(LogEvent* event, int64_t elapsedRealtimeNs);
+
     void resetIfConfigTtlExpiredLocked(const int64_t timestampNs);
 
     void OnConfigUpdatedLocked(
@@ -176,8 +178,7 @@
 
     /* Check if we should send a broadcast if approaching memory limits and if we're over, we
      * actually delete the data. */
-    void flushIfNecessaryLocked(int64_t timestampNs, const ConfigKey& key,
-                                MetricsManager& metricsManager);
+    void flushIfNecessaryLocked(const ConfigKey& key, MetricsManager& metricsManager);
 
     // Maps the isolated uid in the log event to host uid if the log event contains uid fields.
     void mapIsolatedUidToHostUidIfNecessaryLocked(LogEvent* event) const;
@@ -205,7 +206,7 @@
 
     int64_t mLastTimestampSeen = 0;
 
-    long mLastPullerCacheClearTimeSec = 0;
+    int64_t mLastPullerCacheClearTimeSec = 0;
 
     // Last time we wrote data to disk.
     int64_t mLastWriteTimeNs = 0;
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index fd19c9d..262921e 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -38,8 +38,8 @@
 LogEvent::LogEvent(log_msg& msg) {
     mContext =
             create_android_log_parser(msg.msg() + sizeof(uint32_t), msg.len() - sizeof(uint32_t));
-    mLogdTimestampNs = msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec;
-    mLogUid = msg.entry_v4.uid;
+    mLogdTimestampNs = msg.entry.sec * NS_PER_SEC + msg.entry.nsec;
+    mLogUid = msg.entry.uid;
     init(mContext);
     if (mContext) {
         // android_log_destroy will set mContext to NULL
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 6fd0327..0ee156b 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -650,6 +650,7 @@
                     ret.setDouble(value.mValue.double_value);
                     break;
                 default:
+                    return false;
                     break;
             }
             return true;
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index 460b9e0..69e11ed 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -76,9 +76,9 @@
     // Expect only the first flush to trigger a check for byte size since the last two are
     // rate-limited.
     EXPECT_CALL(mockMetricsManager, byteSize()).Times(1);
-    p.flushIfNecessaryLocked(99, key, mockMetricsManager);
-    p.flushIfNecessaryLocked(100, key, mockMetricsManager);
-    p.flushIfNecessaryLocked(101, key, mockMetricsManager);
+    p.flushIfNecessaryLocked(key, mockMetricsManager);
+    p.flushIfNecessaryLocked(key, mockMetricsManager);
+    p.flushIfNecessaryLocked(key, mockMetricsManager);
 }
 
 TEST(StatsLogProcessorTest, TestRateLimitBroadcast) {
@@ -103,7 +103,7 @@
                     StatsdStats::kMaxMetricsBytesPerConfig * .95)));
 
     // Expect only one broadcast despite always returning a size that should trigger broadcast.
-    p.flushIfNecessaryLocked(1, key, mockMetricsManager);
+    p.flushIfNecessaryLocked(key, mockMetricsManager);
     EXPECT_EQ(1, broadcastCount);
 
     // b/73089712
@@ -136,7 +136,7 @@
     EXPECT_CALL(mockMetricsManager, dropData(_)).Times(1);
 
     // Expect to call the onDumpReport and skip the broadcast.
-    p.flushIfNecessaryLocked(1, key, mockMetricsManager);
+    p.flushIfNecessaryLocked(key, mockMetricsManager);
     EXPECT_EQ(0, broadcastCount);
 }
 
diff --git a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
index 5da0fca..9093155 100644
--- a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
@@ -271,19 +271,19 @@
     // Turn screen off.
     event = CreateScreenStateChangedEvent(
             android::view::DISPLAY_STATE_OFF, bucketStartTimeNs + 2 * NS_PER_SEC); // 0:02
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 2 * NS_PER_SEC);
 
     // Turn screen on.
     const int64_t durationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC; // 0:05
     event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, durationStartNs);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), durationStartNs);
 
     // Activate metric.
     const int64_t activationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC; // 0:10
     const int64_t activationEndNs =
             activationStartNs + event_activation1->ttl_seconds() * NS_PER_SEC; // 0:40
     event = CreateAppCrashEvent(111, activationStartNs);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), activationStartNs);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 1);
@@ -296,7 +296,7 @@
     // Expire activation.
     const int64_t expirationNs = activationEndNs + 7 * NS_PER_SEC;
     event = CreateScreenBrightnessChangedEvent(64, expirationNs); // 0:47
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), expirationNs);
     EXPECT_FALSE(metricsManager->isActive());
     EXPECT_FALSE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 2);
@@ -310,24 +310,24 @@
     // Turn off screen 10 seconds after activation expiration.
     const int64_t durationEndNs = activationEndNs + 10 * NS_PER_SEC; // 0:50
     event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, durationEndNs);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(),durationEndNs);
 
     // Turn screen on.
     const int64_t duration2StartNs = durationEndNs + 5 * NS_PER_SEC; // 0:55
     event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, duration2StartNs);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), duration2StartNs);
 
     // Turn off screen.
     const int64_t duration2EndNs = duration2StartNs + 10 * NS_PER_SEC; // 1:05
     event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, duration2EndNs);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), duration2EndNs);
 
     // Activate metric.
     const int64_t activation2StartNs = duration2EndNs + 5 * NS_PER_SEC; // 1:10
     const int64_t activation2EndNs =
             activation2StartNs + event_activation1->ttl_seconds() * NS_PER_SEC; // 1:40
     event = CreateAppCrashEvent(211, activation2StartNs);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), activation2StartNs);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 3);
diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
index f1b6029..b6a6492 100644
--- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
@@ -290,14 +290,14 @@
     std::unique_ptr<LogEvent> event;
 
     event = CreateAppCrashEvent(111, bucketStartTimeNs + 5);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
     EXPECT_FALSE(metricsManager->isActive());
     EXPECT_FALSE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 0);
 
     // Activated by battery save mode.
     event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 1);
@@ -312,12 +312,12 @@
 
     // First processed event.
     event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
 
     // Activated by screen on event.
     event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
                                           bucketStartTimeNs + 20);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
@@ -330,7 +330,7 @@
     // 2nd processed event.
     // The activation by screen_on event expires, but the one by battery save mode is still active.
     event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
@@ -344,11 +344,11 @@
 
     // 3rd processed event.
     event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
 
     // All activations expired.
     event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
     EXPECT_FALSE(metricsManager->isActive());
     EXPECT_FALSE(metricProducer->mIsActive);
     // New broadcast since the config is no longer active.
@@ -364,7 +364,7 @@
     // Re-activate metric via screen on.
     event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
                                           bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 3);
@@ -379,7 +379,7 @@
 
     // 4th processed event.
     event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
 
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
@@ -509,14 +509,14 @@
     std::unique_ptr<LogEvent> event;
 
     event = CreateAppCrashEvent(111, bucketStartTimeNs + 5);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
     EXPECT_FALSE(metricsManager->isActive());
     EXPECT_FALSE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 0);
 
     // Activated by battery save mode.
     event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 1);
@@ -532,12 +532,12 @@
 
     // First processed event.
     event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
 
     // Activated by screen on event.
     event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
                                           bucketStartTimeNs + 20);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
@@ -551,7 +551,7 @@
     // 2nd processed event.
     // The activation by screen_on event expires, but the one by battery save mode is still active.
     event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(),bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
@@ -566,11 +566,11 @@
 
     // 3rd processed event.
     event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
 
     // All activations expired.
     event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
     EXPECT_FALSE(metricsManager->isActive());
     EXPECT_FALSE(metricProducer->mIsActive);
     // New broadcast since the config is no longer active.
@@ -587,7 +587,7 @@
     // Re-activate metric via screen on.
     event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
                                           bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 3);
@@ -603,11 +603,11 @@
 
     // 4th processed event.
     event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
 
     // Re-enable battery saver mode activation.
     event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 3);
@@ -623,11 +623,11 @@
 
     // 5th processed event.
     event = CreateAppCrashEvent(777, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
 
     // Cancel battery saver mode activation.
     event = CreateScreenBrightnessChangedEvent(64, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 3);
@@ -643,7 +643,7 @@
 
     // Screen-on activation expired.
     event = CreateAppCrashEvent(888, bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
     EXPECT_FALSE(metricsManager->isActive());
     EXPECT_FALSE(metricProducer->mIsActive);
     // New broadcast since the config is no longer active.
@@ -658,11 +658,11 @@
     EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
 
     event = CreateAppCrashEvent(999, bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
 
     // Re-enable battery saver mode activation.
     event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 5);
@@ -678,7 +678,7 @@
 
     // Cancel battery saver mode activation.
     event = CreateScreenBrightnessChangedEvent(140, bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
     EXPECT_FALSE(metricsManager->isActive());
     EXPECT_FALSE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 6);
@@ -835,14 +835,14 @@
     std::unique_ptr<LogEvent> event;
 
     event = CreateAppCrashEvent(111, bucketStartTimeNs + 5);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
     EXPECT_FALSE(metricsManager->isActive());
     EXPECT_FALSE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 0);
 
     // Activated by battery save mode.
     event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 1);
@@ -859,12 +859,12 @@
 
     // First processed event.
     event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
 
     // Activated by screen on event.
     event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
                                           bucketStartTimeNs + 20);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
@@ -879,7 +879,7 @@
     // 2nd processed event.
     // The activation by screen_on event expires, but the one by battery save mode is still active.
     event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
@@ -895,11 +895,11 @@
 
     // 3rd processed event.
     event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
 
     // All activations expired.
     event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
     EXPECT_FALSE(metricsManager->isActive());
     EXPECT_FALSE(metricProducer->mIsActive);
     // New broadcast since the config is no longer active.
@@ -917,7 +917,7 @@
     // Re-activate metric via screen on.
     event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
                                           bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 3);
@@ -934,11 +934,11 @@
 
     // 4th processed event.
     event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
 
     // Re-enable battery saver mode activation.
     event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 3);
@@ -955,11 +955,11 @@
 
     // 5th processed event.
     event = CreateAppCrashEvent(777, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
 
     // Cancel battery saver mode and screen on activation.
     event = CreateScreenBrightnessChangedEvent(64, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
     EXPECT_FALSE(metricsManager->isActive());
     EXPECT_FALSE(metricProducer->mIsActive);
     // New broadcast since the config is no longer active.
@@ -976,7 +976,7 @@
 
     // Screen-on activation expired.
     event = CreateAppCrashEvent(888, bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
     EXPECT_FALSE(metricsManager->isActive());
     EXPECT_FALSE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 4);
@@ -991,11 +991,11 @@
     EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
 
     event = CreateAppCrashEvent(999, bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
 
     // Re-enable battery saver mode activation.
     event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 5);
@@ -1012,7 +1012,7 @@
 
     // Cancel battery saver mode and screen on activation.
     event = CreateScreenBrightnessChangedEvent(140, bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
     EXPECT_FALSE(metricsManager->isActive());
     EXPECT_FALSE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 6);
@@ -1170,11 +1170,11 @@
 
     // Event that should be ignored.
     event = CreateAppCrashEvent(111, bucketStartTimeNs + 1);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 1);
 
     // Activate metric via screen on for 2 minutes.
     event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 10);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 1);
@@ -1186,11 +1186,11 @@
 
     // 1st processed event.
     event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
 
     // Enable battery saver mode activation for 5 minutes.
     event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 + 10);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 + 10);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 1);
@@ -1201,12 +1201,12 @@
 
     // 2nd processed event.
     event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 + 40);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 + 40);
 
     // Cancel battery saver mode and screen on activation.
     int64_t firstDeactivation = bucketStartTimeNs + NS_PER_SEC * 61;
     event = CreateScreenBrightnessChangedEvent(64, firstDeactivation);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), firstDeactivation);
     EXPECT_FALSE(metricsManager->isActive());
     EXPECT_FALSE(metricProducer->mIsActive);
     // New broadcast since the config is no longer active.
@@ -1217,11 +1217,11 @@
 
     // Should be ignored
     event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 61 + 80);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 61 + 80);
 
     // Re-enable battery saver mode activation.
     event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 3);
@@ -1233,12 +1233,12 @@
 
     // 3rd processed event.
     event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 80);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 80);
 
     // Cancel battery saver mode activation.
     int64_t secondDeactivation = bucketStartTimeNs + NS_PER_SEC * 60 * 13;
     event = CreateScreenBrightnessChangedEvent(140, secondDeactivation);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), secondDeactivation);
     EXPECT_FALSE(metricsManager->isActive());
     EXPECT_FALSE(metricProducer->mIsActive);
     EXPECT_EQ(broadcastCount, 4);
@@ -1248,7 +1248,7 @@
 
     // Should be ignored.
     event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 13 + 80);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13 + 80);
 
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
@@ -1388,9 +1388,9 @@
     std::unique_ptr<LogEvent> event;
 
     event = CreateAppCrashEvent(111, bucketStartTimeNs + 5);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
     event = CreateMoveToForegroundEvent(1111, bucketStartTimeNs + 5);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
     EXPECT_FALSE(metricsManager->isActive());
     EXPECT_FALSE(metricProducer->mIsActive);
     EXPECT_FALSE(metricProducer2->mIsActive);
@@ -1398,7 +1398,7 @@
 
     // Activated by battery save mode.
     event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_EQ(broadcastCount, 1);
     EXPECT_EQ(activeConfigsBroadcast.size(), 1);
@@ -1424,14 +1424,14 @@
 
     // First processed event.
     event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
     event = CreateMoveToForegroundEvent(2222, bucketStartTimeNs + 15);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
 
     // Activated by screen on event.
     event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
                                           bucketStartTimeNs + 20);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
@@ -1455,9 +1455,9 @@
     // 2nd processed event.
     // The activation by screen_on event expires, but the one by battery save mode is still active.
     event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
     event = CreateMoveToForegroundEvent(3333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_TRUE(metricProducer->mIsActive);
     EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
@@ -1482,15 +1482,15 @@
 
     // 3rd processed event.
     event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
     event = CreateMoveToForegroundEvent(4444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
 
     // All activations expired.
     event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
     event = CreateMoveToForegroundEvent(5555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
     EXPECT_FALSE(metricsManager->isActive());
     // New broadcast since the config is no longer active.
     EXPECT_EQ(broadcastCount, 2);
@@ -1517,7 +1517,7 @@
     // Re-activate metric via screen on.
     event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
                                           bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_EQ(broadcastCount, 3);
     EXPECT_EQ(activeConfigsBroadcast.size(), 1);
@@ -1543,13 +1543,13 @@
 
     // 4th processed event.
     event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
     event = CreateMoveToForegroundEvent(6666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
 
     // Re-enable battery saver mode activation.
     event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_EQ(broadcastCount, 3);
     EXPECT_EQ(activeConfigsBroadcast.size(), 1);
@@ -1575,13 +1575,13 @@
 
     // 5th processed event.
     event = CreateAppCrashEvent(777, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
     event = CreateMoveToForegroundEvent(7777, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
 
     // Cancel battery saver mode and screen on activation.
     event = CreateScreenBrightnessChangedEvent(64, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(),bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
     EXPECT_FALSE(metricsManager->isActive());
     // New broadcast since the config is no longer active.
     EXPECT_EQ(broadcastCount, 4);
@@ -1607,9 +1607,9 @@
 
     // Screen-on activation expired.
     event = CreateAppCrashEvent(888, bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
     event = CreateMoveToForegroundEvent(8888, bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
     EXPECT_FALSE(metricsManager->isActive());
     EXPECT_EQ(broadcastCount, 4);
     EXPECT_EQ(activeConfigsBroadcast.size(), 0);
@@ -1633,13 +1633,13 @@
     EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
 
     event = CreateAppCrashEvent(999, bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
     event = CreateMoveToForegroundEvent(9999, bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
 
     // Re-enable battery saver mode activation.
     event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
     EXPECT_TRUE(metricsManager->isActive());
     EXPECT_EQ(broadcastCount, 5);
     EXPECT_EQ(activeConfigsBroadcast.size(), 1);
@@ -1665,7 +1665,7 @@
 
     // Cancel battery saver mode and screen on activation.
     event = CreateScreenBrightnessChangedEvent(140, bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-    processor.OnLogEvent(event.get());
+    processor.OnLogEvent(event.get(),bucketStartTimeNs + NS_PER_SEC * 60 * 16);
     EXPECT_FALSE(metricsManager->isActive());
     EXPECT_EQ(broadcastCount, 6);
     EXPECT_EQ(activeConfigsBroadcast.size(), 0);
diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
index 455e4bb..b23bf5d 100644
--- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
+++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
@@ -67,7 +67,7 @@
                     throw new IllegalStateException("Could not find provider: " + providerName);
                 }
                 provider = holder.provider;
-                cursor = provider.query(null, Settings.Secure.CONTENT_URI,
+                cursor = provider.query(null, null, Settings.Secure.CONTENT_URI,
                         new String[] {
                             Settings.Secure.VALUE
                         },
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 8d91144..1b9898a 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -200,7 +200,6 @@
 android.app.ContextImpl$1
 android.app.ContextImpl$ApplicationContentResolver
 android.app.ContextImpl
-android.app.DeviceIdleFrameworkInitializer
 android.app.DexLoadReporter
 android.app.Dialog$ListenersHandler
 android.app.Dialog
diff --git a/config/preloaded-classes-extra b/config/preloaded-classes-extra
index 4bfa873..09f393a 100644
--- a/config/preloaded-classes-extra
+++ b/config/preloaded-classes-extra
@@ -1,7 +1,3 @@
-# JobSchedulerFrameworkInitializer must always be preloaded because it registers the job scheduler
-# service wrapper to SystemServiceRegistry.
-android.app.DeviceIdleFrameworkInitializer
-android.app.job.JobSchedulerFrameworkInitializer
 android.icu.impl.coll.CollationRoot
 android.icu.impl.IDNA2003
 android.icu.impl.number.Parse
diff --git a/core/java/android/annotation/UnsupportedAppUsage.java b/core/java/android/annotation/UnsupportedAppUsage.java
index a454df5..204d71d 100644
--- a/core/java/android/annotation/UnsupportedAppUsage.java
+++ b/core/java/android/annotation/UnsupportedAppUsage.java
@@ -83,8 +83,9 @@
      * <p>Possible values are:
      * <ul>
      *     <li>
-     *         {@link android.os.Build.VERSION_CODES#O} or {@link android.os.Build.VERSION_CODES#P},
-     *         to limit access to apps targeting these SDKs (or earlier).
+     *         An API level like {@link android.os.Build.VERSION_CODES#O} - in which case the API is
+     *         available up to and including the specified release. Or, in other words, the API is
+     *         blacklisted (unavailable) from the next API level from the one specified.
      *     </li>
      *     <li>
      *         absent (default value) - All apps can access this API, but doing so may result in
@@ -94,10 +95,6 @@
      *
      * </ul>
      *
-     * Note, if this is set to {@link android.os.Build.VERSION_CODES#O}, apps targeting O
-     * maintenance releases will also be allowed to use the API, and similarly for any future
-     * maintenance releases of P.
-     *
      * @return The maximum value for an apps targetSdkVersion in order to access this API.
      */
     int maxTargetSdk() default Integer.MAX_VALUE;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 2c57622..9872e30 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2563,9 +2563,12 @@
     }
 
     /**
-     * Report to the system that your app is now fully drawn, purely for diagnostic
-     * purposes (calling it does not impact the visible behavior of the activity).
-     * This is only used to help instrument application launch times, so that the
+     * Report to the system that your app is now fully drawn, for diagnostic and
+     * optimization purposes.  The system may adjust optimizations to prioritize
+     * work that happens before reportFullyDrawn is called, to improve app startup.
+     * Misrepresenting the startup window by calling reportFullyDrawn too late or too
+     * early may decrease application and startup performance.<p>
+     * This is also used to help instrument application launch times, so that the
      * app can report when it is fully in a usable state; without this, the only thing
      * the system itself can determine is the point at which the activity's window
      * is <em>first</em> drawn and displayed.  To participate in app launch time
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 7f597fe..1e78fc1 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -163,7 +163,7 @@
         }
 
         @Override
-        public void onUidStateChanged(int uid, int procState, long procStateSeq) {
+        public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) {
             mListener.onUidImportance(uid, RunningAppProcessInfo.procStateToImportanceForClient(
                     procState, mContext));
         }
@@ -432,7 +432,6 @@
     public static final int USER_OP_ERROR_RELATED_USERS_CANNOT_STOP = -4;
 
     /**
-     * @hide
      * Process states, describing the kind of state a particular process is in.
      * When updating these, make sure to also check all related references to the
      * constant in code, and update these arrays:
@@ -443,7 +442,34 @@
      * @see com.android.server.am.ProcessList#sSameAwakePssTimes
      * @see com.android.server.am.ProcessList#sTestFirstPssTimes
      * @see com.android.server.am.ProcessList#sTestSamePssTimes
+     * @hide
      */
+    @IntDef(flag = false, prefix = { "PROCESS_STATE_" }, value = {
+        PROCESS_STATE_UNKNOWN, // -1
+        PROCESS_STATE_PERSISTENT, // 0
+        PROCESS_STATE_PERSISTENT_UI,
+        PROCESS_STATE_TOP,
+        PROCESS_STATE_BOUND_TOP,
+        PROCESS_STATE_FOREGROUND_SERVICE,
+        PROCESS_STATE_BOUND_FOREGROUND_SERVICE,
+        PROCESS_STATE_IMPORTANT_FOREGROUND,
+        PROCESS_STATE_IMPORTANT_BACKGROUND,
+        PROCESS_STATE_TRANSIENT_BACKGROUND,
+        PROCESS_STATE_BACKUP,
+        PROCESS_STATE_SERVICE,
+        PROCESS_STATE_RECEIVER,
+        PROCESS_STATE_TOP_SLEEPING,
+        PROCESS_STATE_HEAVY_WEIGHT,
+        PROCESS_STATE_HOME,
+        PROCESS_STATE_LAST_ACTIVITY,
+        PROCESS_STATE_CACHED_ACTIVITY,
+        PROCESS_STATE_CACHED_ACTIVITY_CLIENT,
+        PROCESS_STATE_CACHED_RECENT,
+        PROCESS_STATE_CACHED_EMPTY,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ProcessState {}
+
 
     /** @hide Not a real process state. */
     public static final int PROCESS_STATE_UNKNOWN = -1;
@@ -459,78 +485,98 @@
     @UnsupportedAppUsage
     public static final int PROCESS_STATE_TOP = 2;
 
-    /** @hide Process is hosting a foreground service with location type. */
-    public static final int PROCESS_STATE_FOREGROUND_SERVICE_LOCATION = 3;
-
     /** @hide Process is bound to a TOP app. This is ranked below SERVICE_LOCATION so that
      * it doesn't get the capability of location access while-in-use. */
-    public static final int PROCESS_STATE_BOUND_TOP = 4;
+    public static final int PROCESS_STATE_BOUND_TOP = 3;
 
     /** @hide Process is hosting a foreground service. */
     @UnsupportedAppUsage
-    public static final int PROCESS_STATE_FOREGROUND_SERVICE = 5;
+    public static final int PROCESS_STATE_FOREGROUND_SERVICE = 4;
 
     /** @hide Process is hosting a foreground service due to a system binding. */
     @UnsupportedAppUsage
-    public static final int PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 6;
+    public static final int PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 5;
 
     /** @hide Process is important to the user, and something they are aware of. */
-    public static final int PROCESS_STATE_IMPORTANT_FOREGROUND = 7;
+    public static final int PROCESS_STATE_IMPORTANT_FOREGROUND = 6;
 
     /** @hide Process is important to the user, but not something they are aware of. */
     @UnsupportedAppUsage
-    public static final int PROCESS_STATE_IMPORTANT_BACKGROUND = 8;
+    public static final int PROCESS_STATE_IMPORTANT_BACKGROUND = 7;
 
     /** @hide Process is in the background transient so we will try to keep running. */
-    public static final int PROCESS_STATE_TRANSIENT_BACKGROUND = 9;
+    public static final int PROCESS_STATE_TRANSIENT_BACKGROUND = 8;
 
     /** @hide Process is in the background running a backup/restore operation. */
-    public static final int PROCESS_STATE_BACKUP = 10;
+    public static final int PROCESS_STATE_BACKUP = 9;
 
     /** @hide Process is in the background running a service.  Unlike oom_adj, this level
      * is used for both the normal running in background state and the executing
      * operations state. */
     @UnsupportedAppUsage
-    public static final int PROCESS_STATE_SERVICE = 11;
+    public static final int PROCESS_STATE_SERVICE = 10;
 
     /** @hide Process is in the background running a receiver.   Note that from the
      * perspective of oom_adj, receivers run at a higher foreground level, but for our
      * prioritization here that is not necessary and putting them below services means
      * many fewer changes in some process states as they receive broadcasts. */
     @UnsupportedAppUsage
-    public static final int PROCESS_STATE_RECEIVER = 12;
+    public static final int PROCESS_STATE_RECEIVER = 11;
 
     /** @hide Same as {@link #PROCESS_STATE_TOP} but while device is sleeping. */
-    public static final int PROCESS_STATE_TOP_SLEEPING = 13;
+    public static final int PROCESS_STATE_TOP_SLEEPING = 12;
 
     /** @hide Process is in the background, but it can't restore its state so we want
      * to try to avoid killing it. */
-    public static final int PROCESS_STATE_HEAVY_WEIGHT = 14;
+    public static final int PROCESS_STATE_HEAVY_WEIGHT = 13;
 
     /** @hide Process is in the background but hosts the home activity. */
     @UnsupportedAppUsage
-    public static final int PROCESS_STATE_HOME = 15;
+    public static final int PROCESS_STATE_HOME = 14;
 
     /** @hide Process is in the background but hosts the last shown activity. */
-    public static final int PROCESS_STATE_LAST_ACTIVITY = 16;
+    public static final int PROCESS_STATE_LAST_ACTIVITY = 15;
 
     /** @hide Process is being cached for later use and contains activities. */
     @UnsupportedAppUsage
-    public static final int PROCESS_STATE_CACHED_ACTIVITY = 17;
+    public static final int PROCESS_STATE_CACHED_ACTIVITY = 16;
 
     /** @hide Process is being cached for later use and is a client of another cached
      * process that contains activities. */
-    public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 18;
+    public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 17;
 
     /** @hide Process is being cached for later use and has an activity that corresponds
      * to an existing recent task. */
-    public static final int PROCESS_STATE_CACHED_RECENT = 19;
+    public static final int PROCESS_STATE_CACHED_RECENT = 18;
 
     /** @hide Process is being cached for later use and is empty. */
-    public static final int PROCESS_STATE_CACHED_EMPTY = 20;
+    public static final int PROCESS_STATE_CACHED_EMPTY = 19;
 
     /** @hide Process does not exist. */
-    public static final int PROCESS_STATE_NONEXISTENT = 21;
+    public static final int PROCESS_STATE_NONEXISTENT = 20;
+
+    /**
+     * The set of flags for process capability.
+     * @hide
+     */
+    @IntDef(flag = true, prefix = { "PROCESS_CAPABILITY_" }, value = {
+            PROCESS_CAPABILITY_NONE,
+            PROCESS_CAPABILITY_FOREGROUND_LOCATION,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ProcessCapability {}
+
+    /** @hide Process does not have any capability */
+    @TestApi
+    public static final int PROCESS_CAPABILITY_NONE = 0;
+
+    /** @hide Process can access location while in foreground */
+    @TestApi
+    public static final int PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1 << 0;
+
+    /** @hide all capabilities, the ORing of all flags in {@link ProcessCapability}*/
+    @TestApi
+    public static final int PROCESS_CAPABILITY_ALL = PROCESS_CAPABILITY_FOREGROUND_LOCATION;
 
     // NOTE: If PROCESS_STATEs are added, then new fields must be added
     // to frameworks/base/core/proto/android/app/enums.proto and the following method must
@@ -557,7 +603,6 @@
                 return AppProtoEnums.PROCESS_STATE_TOP;
             case PROCESS_STATE_BOUND_TOP:
                 return AppProtoEnums.PROCESS_STATE_BOUND_TOP;
-            case PROCESS_STATE_FOREGROUND_SERVICE_LOCATION:
             case PROCESS_STATE_FOREGROUND_SERVICE:
                 return AppProtoEnums.PROCESS_STATE_FOREGROUND_SERVICE;
             case PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
@@ -612,8 +657,7 @@
 
     /** @hide Is this a foreground service type? */
     public static boolean isForegroundService(int procState) {
-        return procState == PROCESS_STATE_FOREGROUND_SERVICE_LOCATION
-                || procState == PROCESS_STATE_FOREGROUND_SERVICE;
+        return procState == PROCESS_STATE_FOREGROUND_SERVICE;
     }
 
     /** @hide requestType for assist context: only basic information. */
@@ -2930,7 +2974,7 @@
                 return IMPORTANCE_PERCEPTIBLE;
             } else if (procState >= PROCESS_STATE_IMPORTANT_FOREGROUND) {
                 return IMPORTANCE_VISIBLE;
-            } else if (procState >= PROCESS_STATE_FOREGROUND_SERVICE_LOCATION) {
+            } else if (procState >= PROCESS_STATE_FOREGROUND_SERVICE) {
                 return IMPORTANCE_FOREGROUND_SERVICE;
             } else {
                 return IMPORTANCE_FOREGROUND;
@@ -4087,7 +4131,7 @@
      * Action an app can implement to handle reports from {@link #setWatchHeapLimit(long)}.
      * If your package has an activity handling this action, it will be launched with the
      * heap data provided to it the same way as {@link Intent#ACTION_SEND}.  Note that to
-     * match the activty must support this action and a MIME type of "*&#47;*".
+     * match, the activity must support this action and a MIME type of "*&#47;*".
      */
     public static final String ACTION_REPORT_HEAP_LIMIT = "android.app.action.REPORT_HEAP_LIMIT";
 
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index d5e41f0..765c358 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -282,10 +282,14 @@
     /**
      * Uid state: The UID is running a foreground service of location type.
      * The lower the UID state the more important the UID is for the user.
+     * This uid state is a counterpart to PROCESS_STATE_FOREGROUND_SERVICE_LOCATION which has been
+     * deprecated.
      * @hide
+     * @deprecated
      */
     @TestApi
     @SystemApi
+    @Deprecated
     public static final int UID_STATE_FOREGROUND_SERVICE_LOCATION = 300;
 
     /**
@@ -298,13 +302,6 @@
     public static final int UID_STATE_FOREGROUND_SERVICE = 400;
 
     /**
-     * The max, which is min priority, UID state for which any app op
-     * would be considered as performed in the foreground.
-     * @hide
-     */
-    public static final int UID_STATE_MAX_LAST_NON_RESTRICTED = UID_STATE_FOREGROUND_SERVICE;
-
-    /**
      * Uid state: The UID is a foreground app. The lower the UID
      * state the more important the UID is for the user.
      * @hide
@@ -314,6 +311,13 @@
     public static final int UID_STATE_FOREGROUND = 500;
 
     /**
+     * The max, which is min priority, UID state for which any app op
+     * would be considered as performed in the foreground.
+     * @hide
+     */
+    public static final int UID_STATE_MAX_LAST_NON_RESTRICTED = UID_STATE_FOREGROUND;
+
+    /**
      * Uid state: The UID is a background app. The lower the UID
      * state the more important the UID is for the user.
      * @hide
@@ -344,47 +348,25 @@
     public static final int MIN_PRIORITY_UID_STATE = UID_STATE_CACHED;
 
     /**
-     * Resolves the first unrestricted state given an app op. Location is
-     * special as we want to allow its access only if a dedicated location
-     * foreground service is running. For other ops we consider any foreground
-     * service as a foreground state.
-     *
+     * Resolves the first unrestricted state given an app op.
      * @param op The op to resolve.
      * @return The last restricted UID state.
      *
      * @hide
      */
     public static int resolveFirstUnrestrictedUidState(int op) {
-        switch (op) {
-            case OP_FINE_LOCATION:
-            case OP_COARSE_LOCATION:
-            case OP_MONITOR_LOCATION:
-            case OP_MONITOR_HIGH_POWER_LOCATION: {
-                return UID_STATE_FOREGROUND_SERVICE_LOCATION;
-            }
-        }
-        return UID_STATE_FOREGROUND_SERVICE;
+        return UID_STATE_FOREGROUND;
     }
 
     /**
-     * Resolves the last restricted state given an app op. Location is
-     * special as we want to allow its access only if a dedicated location
-     * foreground service is running. For other ops we consider any foreground
-     * service as a foreground state.
-     *
+     * Resolves the last restricted state given an app op.
      * @param op The op to resolve.
      * @return The last restricted UID state.
      *
      * @hide
      */
     public static int resolveLastRestrictedUidState(int op) {
-        switch (op) {
-            case OP_FINE_LOCATION:
-            case OP_COARSE_LOCATION: {
-                return UID_STATE_FOREGROUND_SERVICE;
-            }
-        }
-        return UID_STATE_FOREGROUND;
+        return UID_STATE_BACKGROUND;
     }
 
     /** @hide Note: Keep these sorted */
@@ -2822,12 +2804,12 @@
                             LongSparseArray.StringParcelling.class);
 
             return new OpFeatureEntry.Builder(source.readBoolean(),
-                    (LongSparseLongArray) longSparseLongArrayParcelling.unparcel(source),
-                    (LongSparseLongArray) longSparseLongArrayParcelling.unparcel(source),
-                    (LongSparseLongArray) longSparseLongArrayParcelling.unparcel(source),
-                    (LongSparseLongArray) longSparseLongArrayParcelling.unparcel(source),
-                    (LongSparseArray<String>) longSparseStringArrayParcelling.unparcel(source),
-                    (LongSparseArray<String>) longSparseStringArrayParcelling.unparcel(source));
+                    longSparseLongArrayParcelling.unparcel(source),
+                    longSparseLongArrayParcelling.unparcel(source),
+                    longSparseLongArrayParcelling.unparcel(source),
+                    longSparseLongArrayParcelling.unparcel(source),
+                    longSparseStringArrayParcelling.unparcel(source),
+                    longSparseStringArrayParcelling.unparcel(source));
         }
     }
 
@@ -4603,7 +4585,6 @@
          *
          * @param fromUidState The UID state from which to query. Could be one of
          * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
-         * {@link #UID_STATE_FOREGROUND_SERVICE_LOCATION},
          * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
          * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
          * @param toUidState The UID state to which to query.
@@ -4664,7 +4645,6 @@
          *
          * @param fromUidState The UID state from which to query. Could be one of
          * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
-         * {@link #UID_STATE_FOREGROUND_SERVICE_LOCATION},
          * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
          * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
          * @param toUidState The UID state to which to query.
@@ -4728,7 +4708,6 @@
          *
          * @param fromUidState The UID state from which to query. Could be one of
          * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
-         * {@link #UID_STATE_FOREGROUND_SERVICE_LOCATION},
          * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
          * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
          * @param toUidState The UID state from which to query.
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index eb2b2bc..466c1a9 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -73,6 +73,7 @@
 import android.system.Os;
 import android.system.OsConstants;
 import android.system.StructStat;
+import android.text.TextUtils;
 import android.util.AndroidRuntimeException;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -1341,6 +1342,19 @@
     }
 
     @Override
+    public void sendOrderedBroadcast(Intent intent, String receiverPermission,
+            String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler,
+            int initialCode, String initialData, @Nullable Bundle initialExtras) {
+        int intAppOp = AppOpsManager.OP_NONE;
+        if (!TextUtils.isEmpty(receiverAppOp)) {
+            intAppOp = AppOpsManager.strOpToOp(receiverAppOp);
+        }
+        sendOrderedBroadcastAsUser(intent, getUser(),
+                receiverPermission, intAppOp, resultReceiver, scheduler, initialCode, initialData,
+                initialExtras);
+    }
+
+    @Override
     @Deprecated
     public void sendStickyBroadcast(Intent intent) {
         warnIfCallingFromSystemProcess();
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index f591441..770e5f7 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -70,6 +70,7 @@
 import android.view.IRecentsAnimationRunner;
 import android.view.RemoteAnimationDefinition;
 import android.view.RemoteAnimationAdapter;
+import android.view.WindowContainerTransaction;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.policy.IKeyguardDismissCallback;
@@ -220,6 +221,7 @@
     void setTaskResizeable(int taskId, int resizeableMode);
     void toggleFreeformWindowingMode(in IBinder token);
     void resizeTask(int taskId, in Rect bounds, int resizeMode);
+    void applyContainerTransaction(in WindowContainerTransaction t);
     void moveStackToDisplay(int stackId, int displayId);
     void removeStack(int stackId);
 
diff --git a/core/java/android/app/IUidObserver.aidl b/core/java/android/app/IUidObserver.aidl
index e116d98..7713e25 100644
--- a/core/java/android/app/IUidObserver.aidl
+++ b/core/java/android/app/IUidObserver.aidl
@@ -50,8 +50,9 @@
      * @param procState The updated process state for the uid.
      * @param procStateSeq The sequence no. associated with process state change of the uid,
      *                     see UidRecord.procStateSeq for details.
+     * @param capability the updated process capability for the uid.
      */
-    void onUidStateChanged(int uid, int procState, long procStateSeq);
+    void onUidStateChanged(int uid, int procState, long procStateSeq, int capability);
 
     // =============== End of transactions used on native side as well ============================
 
diff --git a/core/java/android/app/NotificationHistory.aidl b/core/java/android/app/NotificationHistory.aidl
new file mode 100644
index 0000000..8150e74
--- /dev/null
+++ b/core/java/android/app/NotificationHistory.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.app;
+
+parcelable NotificationHistory;
\ No newline at end of file
diff --git a/core/java/android/app/NotificationHistory.java b/core/java/android/app/NotificationHistory.java
new file mode 100644
index 0000000..c35246b
--- /dev/null
+++ b/core/java/android/app/NotificationHistory.java
@@ -0,0 +1,506 @@
+/*
+ * 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.app;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.graphics.drawable.Icon;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * @hide
+ */
+public final class NotificationHistory implements Parcelable {
+
+    /**
+     * A historical notification. Any new fields added here should also be added to
+     * {@link #readNotificationFromParcel} and
+     * {@link #writeNotificationToParcel(HistoricalNotification, Parcel, int)}.
+     */
+    public static final class HistoricalNotification {
+        private String mPackage;
+        private String mChannelName;
+        private String mChannelId;
+        private int mUid;
+        private @UserIdInt int mUserId;
+        private long mPostedTimeMs;
+        private String mTitle;
+        private String mText;
+        private Icon mIcon;
+
+        private HistoricalNotification() {}
+
+        public String getPackage() {
+            return mPackage;
+        }
+
+        public String getChannelName() {
+            return mChannelName;
+        }
+
+        public String getChannelId() {
+            return mChannelId;
+        }
+
+        public int getUid() {
+            return mUid;
+        }
+
+        public int getUserId() {
+            return mUserId;
+        }
+
+        public long getPostedTimeMs() {
+            return mPostedTimeMs;
+        }
+
+        public String getTitle() {
+            return mTitle;
+        }
+
+        public String getText() {
+            return mText;
+        }
+
+        public Icon getIcon() {
+            return mIcon;
+        }
+
+        public String getKey() {
+            return mPackage + "|" + mUid + "|" + mPostedTimeMs;
+        }
+
+        @Override
+        public String toString() {
+            return "HistoricalNotification{" +
+                    "key='" + getKey() + '\'' +
+                    ", mChannelName='" + mChannelName + '\'' +
+                    ", mChannelId='" + mChannelId + '\'' +
+                    ", mUserId=" + mUserId +
+                    ", mTitle='" + mTitle + '\'' +
+                    ", mText='" + mText + '\'' +
+                    ", mIcon=" + mIcon +
+                    '}';
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            HistoricalNotification that = (HistoricalNotification) o;
+            boolean iconsAreSame = getIcon() == null && that.getIcon() == null
+                    || (getIcon() != null && that.getIcon() != null
+                    && getIcon().sameAs(that.getIcon()));
+            return getUid() == that.getUid() &&
+                    getUserId() == that.getUserId() &&
+                    getPostedTimeMs() == that.getPostedTimeMs() &&
+                    Objects.equals(getPackage(), that.getPackage()) &&
+                    Objects.equals(getChannelName(), that.getChannelName()) &&
+                    Objects.equals(getChannelId(), that.getChannelId()) &&
+                    Objects.equals(getTitle(), that.getTitle()) &&
+                    Objects.equals(getText(), that.getText()) &&
+                    iconsAreSame;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(getPackage(), getChannelName(), getChannelId(), getUid(),
+                    getUserId(),
+                    getPostedTimeMs(), getTitle(), getText(), getIcon());
+        }
+
+        public static final class Builder {
+            private String mPackage;
+            private String mChannelName;
+            private String mChannelId;
+            private int mUid;
+            private @UserIdInt int mUserId;
+            private long mPostedTimeMs;
+            private String mTitle;
+            private String mText;
+            private Icon mIcon;
+
+            public Builder() {}
+
+            public Builder setPackage(String aPackage) {
+                mPackage = aPackage;
+                return this;
+            }
+
+            public Builder setChannelName(String channelName) {
+                mChannelName = channelName;
+                return this;
+            }
+
+            public Builder setChannelId(String channelId) {
+                mChannelId = channelId;
+                return this;
+            }
+
+            public Builder setUid(int uid) {
+                mUid = uid;
+                return this;
+            }
+
+            public Builder setUserId(int userId) {
+                mUserId = userId;
+                return this;
+            }
+
+            public Builder setPostedTimeMs(long postedTimeMs) {
+                mPostedTimeMs = postedTimeMs;
+                return this;
+            }
+
+            public Builder setTitle(String title) {
+                mTitle = title;
+                return this;
+            }
+
+            public Builder setText(String text) {
+                mText = text;
+                return this;
+            }
+
+            public Builder setIcon(Icon icon) {
+                mIcon = icon;
+                return this;
+            }
+
+            public HistoricalNotification build() {
+                HistoricalNotification n = new HistoricalNotification();
+                n.mPackage = mPackage;
+                n.mChannelName = mChannelName;
+                n.mChannelId = mChannelId;
+                n.mUid = mUid;
+                n.mUserId = mUserId;
+                n.mPostedTimeMs = mPostedTimeMs;
+                n.mTitle = mTitle;
+                n.mText = mText;
+                n.mIcon = mIcon;
+                return n;
+            }
+        }
+    }
+
+    // Only used when creating the resulting history. Not used for reading/unparceling.
+    private List<HistoricalNotification> mNotificationsToWrite = new ArrayList<>();
+    // ditto
+    private Set<String> mStringsToWrite = new HashSet<>();
+
+    // Mostly used for reading/unparceling events.
+    private Parcel mParcel = null;
+    private int mHistoryCount;
+    private int mIndex = 0;
+
+    // Sorted array of commonly used strings to shrink the size of the parcel. populated from
+    // mStringsToWrite on write and the parcel on read.
+    private String[] mStringPool;
+
+    /**
+     * Construct the iterator from a parcel.
+     */
+    private NotificationHistory(Parcel in) {
+        byte[] bytes = in.readBlob();
+        Parcel data = Parcel.obtain();
+        data.unmarshall(bytes, 0, bytes.length);
+        data.setDataPosition(0);
+        mHistoryCount = data.readInt();
+        mIndex = data.readInt();
+        if (mHistoryCount > 0) {
+            mStringPool = data.createStringArray();
+
+            final int listByteLength = data.readInt();
+            final int positionInParcel = data.readInt();
+            mParcel = Parcel.obtain();
+            mParcel.setDataPosition(0);
+            mParcel.appendFrom(data, data.dataPosition(), listByteLength);
+            mParcel.setDataSize(mParcel.dataPosition());
+            mParcel.setDataPosition(positionInParcel);
+        }
+    }
+
+    /**
+     * Create an empty iterator.
+     */
+    public NotificationHistory() {
+        mHistoryCount = 0;
+    }
+
+    /**
+     * Returns whether or not there are more events to read using {@link #getNextNotification()}.
+     *
+     * @return true if there are more events, false otherwise.
+     */
+    public boolean hasNextNotification() {
+        return mIndex < mHistoryCount;
+    }
+
+    /**
+     * Retrieve the next {@link HistoricalNotification} from the collection and put the
+     * resulting data into {@code notificationOut}.
+     *
+     * @return The next {@link HistoricalNotification} or null if there are no more notifications.
+     */
+    public @Nullable HistoricalNotification getNextNotification() {
+        if (!hasNextNotification()) {
+            return null;
+        }
+
+        HistoricalNotification n = readNotificationFromParcel(mParcel);
+
+        mIndex++;
+        if (!hasNextNotification()) {
+            mParcel.recycle();
+            mParcel = null;
+        }
+        return n;
+    }
+
+    /**
+     * Adds all of the pooled strings that have been read from disk
+     */
+    public void addPooledStrings(@NonNull List<String> strings) {
+        mStringsToWrite.addAll(strings);
+    }
+
+    /**
+     * Builds the pooled strings from pending notifications. Useful if the pooled strings on
+     * disk contains strings that aren't relevant to the notifications in our collection.
+     */
+    public void poolStringsFromNotifications() {
+        mStringsToWrite.clear();
+        for (int i = 0; i < mNotificationsToWrite.size(); i++) {
+            final HistoricalNotification notification = mNotificationsToWrite.get(i);
+            mStringsToWrite.add(notification.getPackage());
+            mStringsToWrite.add(notification.getChannelName());
+            mStringsToWrite.add(notification.getChannelId());
+        }
+    }
+
+    /**
+     * Used when populating a history from disk; adds an historical notification.
+     */
+    public void addNotificationToWrite(@NonNull HistoricalNotification notification) {
+        if (notification == null) {
+            return;
+        }
+        mNotificationsToWrite.add(notification);
+        mHistoryCount++;
+    }
+
+    /**
+     * Removes a package's historical notifications and regenerates the string pool
+     */
+    public void removeNotificationsFromWrite(String packageName) {
+        for (int i = mNotificationsToWrite.size() - 1; i >= 0; i--) {
+            if (packageName.equals(mNotificationsToWrite.get(i).getPackage())) {
+                mNotificationsToWrite.remove(i);
+            }
+        }
+        poolStringsFromNotifications();
+    }
+
+    /**
+     * Gets pooled strings in order to write them to disk
+     */
+    public @NonNull String[] getPooledStringsToWrite() {
+        String[] stringsToWrite = mStringsToWrite.toArray(new String[]{});
+        Arrays.sort(stringsToWrite);
+        return stringsToWrite;
+    }
+
+    /**
+     * Gets the historical notifications in order to write them to disk
+     */
+    public @NonNull List<HistoricalNotification> getNotificationsToWrite() {
+        return mNotificationsToWrite;
+    }
+
+    /**
+     * Gets the number of notifications in the collection
+     */
+    public int getHistoryCount() {
+        return mHistoryCount;
+    }
+
+    private int findStringIndex(String str) {
+        final int index = Arrays.binarySearch(mStringPool, str);
+        if (index < 0) {
+            throw new IllegalStateException("String '" + str + "' is not in the string pool");
+        }
+        return index;
+    }
+
+    /**
+     * Writes a single notification to the parcel. Modify this when updating member variables of
+     * {@link HistoricalNotification}.
+     */
+    private void writeNotificationToParcel(HistoricalNotification notification, Parcel p,
+            int flags) {
+        final int packageIndex;
+        if (notification.mPackage != null) {
+            packageIndex = findStringIndex(notification.mPackage);
+        } else {
+            packageIndex = -1;
+        }
+
+        final int channelNameIndex;
+        if (notification.getChannelName() != null) {
+            channelNameIndex = findStringIndex(notification.getChannelName());
+        } else {
+            channelNameIndex = -1;
+        }
+
+        final int channelIdIndex;
+        if (notification.getChannelId() != null) {
+            channelIdIndex = findStringIndex(notification.getChannelId());
+        } else {
+            channelIdIndex = -1;
+        }
+
+        p.writeInt(packageIndex);
+        p.writeInt(channelNameIndex);
+        p.writeInt(channelIdIndex);
+        p.writeInt(notification.getUid());
+        p.writeInt(notification.getUserId());
+        p.writeLong(notification.getPostedTimeMs());
+        p.writeString(notification.getTitle());
+        p.writeString(notification.getText());
+        notification.getIcon().writeToParcel(p, flags);
+    }
+
+    /**
+     * Reads a single notification from the parcel. Modify this when updating member variables of
+     * {@link HistoricalNotification}.
+     */
+    private HistoricalNotification readNotificationFromParcel(Parcel p) {
+        HistoricalNotification.Builder notificationOut = new HistoricalNotification.Builder();
+        final int packageIndex = p.readInt();
+        if (packageIndex >= 0) {
+            notificationOut.mPackage = mStringPool[packageIndex];
+        } else {
+            notificationOut.mPackage = null;
+        }
+
+        final int channelNameIndex = p.readInt();
+        if (channelNameIndex >= 0) {
+            notificationOut.setChannelName(mStringPool[channelNameIndex]);
+        } else {
+            notificationOut.setChannelName(null);
+        }
+
+        final int channelIdIndex = p.readInt();
+        if (channelIdIndex >= 0) {
+            notificationOut.setChannelId(mStringPool[channelIdIndex]);
+        } else {
+            notificationOut.setChannelId(null);
+        }
+
+        notificationOut.setUid(p.readInt());
+        notificationOut.setUserId(p.readInt());
+        notificationOut.setPostedTimeMs(p.readLong());
+        notificationOut.setTitle(p.readString());
+        notificationOut.setText(p.readString());
+        notificationOut.setIcon(Icon.CREATOR.createFromParcel(p));
+
+        return notificationOut.build();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        Parcel data = Parcel.obtain();
+        data.writeInt(mHistoryCount);
+        data.writeInt(mIndex);
+        if (mHistoryCount > 0) {
+            mStringPool = getPooledStringsToWrite();
+            data.writeStringArray(mStringPool);
+
+            if (!mNotificationsToWrite.isEmpty()) {
+                // typically system_server to a process
+
+                // Write out the events
+                Parcel p = Parcel.obtain();
+                try {
+                    p.setDataPosition(0);
+                    for (int i = 0; i < mHistoryCount; i++) {
+                        final HistoricalNotification notification = mNotificationsToWrite.get(i);
+                        writeNotificationToParcel(notification, p, flags);
+                    }
+
+                    final int listByteLength = p.dataPosition();
+
+                    // Write the total length of the data.
+                    data.writeInt(listByteLength);
+
+                    // Write our current position into the data.
+                    data.writeInt(0);
+
+                    // Write the data.
+                    data.appendFrom(p, 0, listByteLength);
+                } finally {
+                    p.recycle();
+                }
+
+            } else if (mParcel != null) {
+                // typically process to process as mNotificationsToWrite is not populated on
+                // unparcel.
+
+                // Write the total length of the data.
+                data.writeInt(mParcel.dataSize());
+
+                // Write out current position into the data.
+                data.writeInt(mParcel.dataPosition());
+
+                // Write the data.
+                data.appendFrom(mParcel, 0, mParcel.dataSize());
+            } else {
+                throw new IllegalStateException(
+                        "Either mParcel or mNotificationsToWrite must not be null");
+            }
+        }
+        // Data can be too large for a transact. Write the data as a Blob, which will be written to
+        // ashmem if too large.
+        dest.writeBlob(data.marshall());
+    }
+
+    public static final @NonNull Creator<NotificationHistory> CREATOR
+            = new Creator<NotificationHistory>() {
+        @Override
+        public NotificationHistory createFromParcel(Parcel source) {
+            return new NotificationHistory(source);
+        }
+
+        @Override
+        public NotificationHistory[] newArray(int size) {
+            return new NotificationHistory[size];
+        }
+    };
+}
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 4b4a071..3ad8882 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -94,6 +94,12 @@
  * {@link #FLAG_CANCEL_CURRENT} or {@link #FLAG_UPDATE_CURRENT} to either
  * cancel or modify whatever current PendingIntent is associated with the
  * Intent you are supplying.
+ *
+ * <p>Also note that flags like {@link #FLAG_ONE_SHOT} or {@link #FLAG_IMMUTABLE} describe the
+ * PendingIntent instance and thus, are used to identify it. Any calls to retrieve or modify a
+ * PendingIntent created with these flags will also require these flags to be supplied in
+ * conjunction with others. E.g. To retrieve an existing PendingIntent created with
+ * FLAG_ONE_SHOT, <b>both</b> FLAG_ONE_SHOT and FLAG_NO_CREATE need to be supplied.
  */
 public final class PendingIntent implements Parcelable {
     private final IIntentSender mTarget;
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 8350fa1..629c2bb 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -23,6 +23,7 @@
 import android.app.admin.IDevicePolicyManager;
 import android.app.contentsuggestions.ContentSuggestionsManager;
 import android.app.contentsuggestions.IContentSuggestionsManager;
+import android.app.job.JobSchedulerFrameworkInitializer;
 import android.app.prediction.AppPredictionManager;
 import android.app.role.RoleControllerManager;
 import android.app.role.RoleManager;
@@ -125,6 +126,7 @@
 import android.nfc.NfcManager;
 import android.os.BatteryManager;
 import android.os.BatteryStats;
+import android.os.BatteryStatsManager;
 import android.os.BugreportManager;
 import android.os.Build;
 import android.os.DropBoxManager;
@@ -152,7 +154,6 @@
 import android.os.image.DynamicSystemManager;
 import android.os.image.IDynamicSystemService;
 import android.os.storage.StorageManager;
-import android.telephony.TelephonyRegistryManager;
 import android.permission.PermissionControllerManager;
 import android.permission.PermissionManager;
 import android.print.IPrintManager;
@@ -166,6 +167,7 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.TelephonyRegistryManager;
 import android.telephony.euicc.EuiccCardManager;
 import android.telephony.euicc.EuiccManager;
 import android.telephony.ims.RcsMessageManager;
@@ -1286,7 +1288,20 @@
                         return new DynamicSystemManager(
                                 IDynamicSystemService.Stub.asInterface(b));
                     }});
+        registerService(Context.BATTERY_STATS_SERVICE, BatteryStatsManager.class,
+                new CachedServiceFetcher<BatteryStatsManager>() {
+                    @Override
+                    public BatteryStatsManager createService(ContextImpl ctx)
+                            throws ServiceNotFoundException {
+                        IBinder b = ServiceManager.getServiceOrThrow(
+                                Context.BATTERY_STATS_SERVICE);
+                        return new BatteryStatsManager(
+                                IBatteryStats.Stub.asInterface(b));
+                    }});
         //CHECKSTYLE:ON IndentationCheck
+
+        JobSchedulerFrameworkInitializer.initialize();
+        DeviceIdleFrameworkInitializer.initialize();
     }
 
     /**
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index c400316..f4c6b50 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -440,6 +440,34 @@
     }
 
     /**
+     * Copies the fields specified by mask from delta into this Configuration object.
+     * @hide
+     */
+    public void setTo(@NonNull WindowConfiguration delta, @WindowConfig int mask) {
+        if ((mask & WINDOW_CONFIG_BOUNDS) != 0) {
+            setBounds(delta.mBounds);
+        }
+        if ((mask & WINDOW_CONFIG_APP_BOUNDS) != 0) {
+            setAppBounds(delta.mAppBounds);
+        }
+        if ((mask & WINDOW_CONFIG_WINDOWING_MODE) != 0) {
+            setWindowingMode(delta.mWindowingMode);
+        }
+        if ((mask & WINDOW_CONFIG_ACTIVITY_TYPE) != 0) {
+            setActivityType(delta.mActivityType);
+        }
+        if ((mask & WINDOW_CONFIG_ALWAYS_ON_TOP) != 0) {
+            setAlwaysOnTop(delta.mAlwaysOnTop);
+        }
+        if ((mask & WINDOW_CONFIG_ROTATION) != 0) {
+            setRotation(delta.mRotation);
+        }
+        if ((mask & WINDOW_CONFIG_DISPLAY_WINDOWING_MODE) != 0) {
+            setDisplayWindowingMode(delta.mDisplayWindowingMode);
+        }
+    }
+
+    /**
      * Return a bit mask of the differences between this Configuration object and the given one.
      * Does not change the values of either. Any undefined fields in <var>other</var> are ignored.
      * @param other The configuration to diff against.
diff --git a/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
index 1bb81b1..1e6ab41 100644
--- a/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
+++ b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
@@ -45,6 +45,17 @@
  */
 @SystemApi
 public final class ContentSuggestionsManager {
+    /**
+     * Key into the extras Bundle passed to {@link #provideContextImage(int, Bundle)}.
+     * This can be used to provide the bitmap to
+     * {@link android.service.contentsuggestions.ContentSuggestionsService}.
+     * The value must be a {@link android.graphics.Bitmap} with the
+     * config {@link android.graphics.Bitmap.Config.HARDWARE}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_BITMAP = "android.contentsuggestions.extra.BITMAP";
+
     private static final String TAG = ContentSuggestionsManager.class.getSimpleName();
 
     /**
@@ -70,7 +81,7 @@
      * system content suggestions service.
      *
      * @param taskId of the task to snapshot.
-     * @param imageContextRequestExtras sent with with request to provide implementation specific
+     * @param imageContextRequestExtras sent with request to provide implementation specific
      *                                  extra information.
      */
     public void provideContextImage(
diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java
index 30868bf..97e3f52 100644
--- a/core/java/android/bluetooth/le/ScanRecord.java
+++ b/core/java/android/bluetooth/le/ScanRecord.java
@@ -154,7 +154,7 @@
     }
 
     /**
-     * Returns the local name of the BLE device. The is a UTF-8 encoded string.
+     * Returns the local name of the BLE device. This is a UTF-8 encoded string.
      */
     @Nullable
     public String getDeviceName() {
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index cb35357..9cb73f9 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -42,11 +42,15 @@
 /**
  * System level service for managing companion devices
  *
+ * See <a href="{@docRoot}guide/topics/connectivity/companion-device-pairing">this guide</a>
+ * for a usage example.
+ *
  * <p>To obtain an instance call {@link Context#getSystemService}({@link
  * Context#COMPANION_DEVICE_SERVICE}) Then, call {@link #associate(AssociationRequest,
  * Callback, Handler)} to initiate the flow of associating current package with a
  * device selected by user.</p>
  *
+ * @see CompanionDeviceManager#associate
  * @see AssociationRequest
  */
 @SystemService(Context.COMPANION_DEVICE_SERVICE)
diff --git a/core/java/android/companion/WifiDeviceFilter.java b/core/java/android/companion/WifiDeviceFilter.java
index 62098d5..58bf874 100644
--- a/core/java/android/companion/WifiDeviceFilter.java
+++ b/core/java/android/companion/WifiDeviceFilter.java
@@ -17,17 +17,18 @@
 package android.companion;
 
 import static android.companion.BluetoothDeviceFilterUtils.getDeviceDisplayNameInternal;
-import static android.companion.BluetoothDeviceFilterUtils.patternFromString;
-import static android.companion.BluetoothDeviceFilterUtils.patternToString;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.SuppressLint;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.le.ScanFilter;
+import android.net.MacAddress;
 import android.net.wifi.ScanResult;
 import android.os.Parcel;
-import android.provider.OneTimeUseBuilder;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+import com.android.internal.util.Parcelling;
 
 import java.util.Objects;
 import java.util.regex.Pattern;
@@ -37,30 +38,38 @@
  *
  * @see ScanFilter
  */
+@DataClass(
+        genParcelable = true,
+        genAidl = false,
+        genBuilder = true,
+        genEqualsHashCode = true,
+        genHiddenGetters = true)
 public final class WifiDeviceFilter implements DeviceFilter<ScanResult> {
 
-    private final Pattern mNamePattern;
+    /**
+     * If set, only devices with {@link BluetoothDevice#getName name} matching the given regular
+     * expression will be shown
+     */
+    @DataClass.ParcelWith(Parcelling.BuiltIn.ForPattern.class)
+    private @Nullable Pattern mNamePattern = null;
 
-    private WifiDeviceFilter(Pattern namePattern) {
-        mNamePattern = namePattern;
-    }
+    /**
+     * If set, only devices with BSSID matching the given one will be shown
+     */
+    private @Nullable MacAddress mBssid = null;
 
-    @SuppressLint("ParcelClassLoader")
-    private WifiDeviceFilter(Parcel in) {
-        this(patternFromString(in.readString()));
-    }
-
-    /** @hide */
-    @Nullable
-    public Pattern getNamePattern() {
-        return mNamePattern;
-    }
-
+    /**
+     * If set, only bits at positions set in this mask, will be compared to the given
+     * {@link Builder#setBssid BSSID} filter.
+     */
+    private @NonNull MacAddress mBssidMask = MacAddress.BROADCAST_ADDRESS;
 
     /** @hide */
     @Override
     public boolean matches(ScanResult device) {
-        return BluetoothDeviceFilterUtils.matchesName(getNamePattern(), device);
+        return BluetoothDeviceFilterUtils.matchesName(getNamePattern(), device)
+                && (mBssid == null
+                        || MacAddress.fromString(device.BSSID).matches(mBssid, mBssidMask));
     }
 
     /** @hide */
@@ -75,65 +84,249 @@
         return MEDIUM_TYPE_WIFI;
     }
 
+
+
+    // Code below generated by codegen v1.0.11.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/companion/WifiDeviceFilter.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    @DataClass.Generated.Member
+    /* package-private */ WifiDeviceFilter(
+            @Nullable Pattern namePattern,
+            @Nullable MacAddress bssid,
+            @NonNull MacAddress bssidMask) {
+        this.mNamePattern = namePattern;
+        this.mBssid = bssid;
+        this.mBssidMask = bssidMask;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mBssidMask);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * If set, only devices with {@link BluetoothDevice#getName name} matching the given regular
+     * expression will be shown
+     *
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public @Nullable Pattern getNamePattern() {
+        return mNamePattern;
+    }
+
+    /**
+     * If set, only devices with BSSID matching the given one will be shown
+     *
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public @Nullable MacAddress getBssid() {
+        return mBssid;
+    }
+
+    /**
+     * If set, only bits at positions set in this mask, will be compared to the given
+     * {@link Builder#setBssid BSSID} filter.
+     *
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public @NonNull MacAddress getBssidMask() {
+        return mBssidMask;
+    }
+
     @Override
-    public boolean equals(Object o) {
+    @DataClass.Generated.Member
+    public boolean equals(@Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(WifiDeviceFilter other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
         WifiDeviceFilter that = (WifiDeviceFilter) o;
-        return Objects.equals(mNamePattern, that.mNamePattern);
+        //noinspection PointlessBooleanExpression
+        return true
+                && Objects.equals(mNamePattern, that.mNamePattern)
+                && Objects.equals(mBssid, that.mBssid)
+                && Objects.equals(mBssidMask, that.mBssidMask);
     }
 
     @Override
+    @DataClass.Generated.Member
     public int hashCode() {
-        return Objects.hash(mNamePattern);
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + Objects.hashCode(mNamePattern);
+        _hash = 31 * _hash + Objects.hashCode(mBssid);
+        _hash = 31 * _hash + Objects.hashCode(mBssidMask);
+        return _hash;
     }
 
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(patternToString(getNamePattern()));
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    public static final @android.annotation.NonNull Creator<WifiDeviceFilter> CREATOR
-            = new Creator<WifiDeviceFilter>() {
-        @Override
-        public WifiDeviceFilter createFromParcel(Parcel in) {
-            return new WifiDeviceFilter(in);
+    @DataClass.Generated.Member
+    static Parcelling<Pattern> sParcellingForNamePattern =
+            Parcelling.Cache.get(
+                    Parcelling.BuiltIn.ForPattern.class);
+    static {
+        if (sParcellingForNamePattern == null) {
+            sParcellingForNamePattern = Parcelling.Cache.put(
+                    new Parcelling.BuiltIn.ForPattern());
         }
+    }
 
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        byte flg = 0;
+        if (mNamePattern != null) flg |= 0x1;
+        if (mBssid != null) flg |= 0x2;
+        dest.writeByte(flg);
+        sParcellingForNamePattern.parcel(mNamePattern, dest, flags);
+        if (mBssid != null) dest.writeTypedObject(mBssid, flags);
+        dest.writeTypedObject(mBssidMask, flags);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ WifiDeviceFilter(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte flg = in.readByte();
+        Pattern namePattern = sParcellingForNamePattern.unparcel(in);
+        MacAddress bssid = (flg & 0x2) == 0 ? null : (MacAddress) in.readTypedObject(MacAddress.CREATOR);
+        MacAddress bssidMask = (MacAddress) in.readTypedObject(MacAddress.CREATOR);
+
+        this.mNamePattern = namePattern;
+        this.mBssid = bssid;
+        this.mBssidMask = bssidMask;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mBssidMask);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<WifiDeviceFilter> CREATOR
+            = new Parcelable.Creator<WifiDeviceFilter>() {
         @Override
         public WifiDeviceFilter[] newArray(int size) {
             return new WifiDeviceFilter[size];
         }
+
+        @Override
+        public WifiDeviceFilter createFromParcel(@NonNull Parcel in) {
+            return new WifiDeviceFilter(in);
+        }
     };
 
     /**
-     * Builder for {@link WifiDeviceFilter}
+     * A builder for {@link WifiDeviceFilter}
      */
-    public static final class Builder extends OneTimeUseBuilder<WifiDeviceFilter> {
-        private Pattern mNamePattern;
+    @SuppressWarnings("WeakerAccess")
+    @DataClass.Generated.Member
+    public static final class Builder {
+
+        private @Nullable Pattern mNamePattern;
+        private @Nullable MacAddress mBssid;
+        private @NonNull MacAddress mBssidMask;
+
+        private long mBuilderFieldsSet = 0L;
+
+        public Builder() {
+        }
 
         /**
-         * @param regex if set, only devices with {@link BluetoothDevice#getName name} matching the
-         *              given regular expression will be shown
-         * @return self for chaining
+         * If set, only devices with {@link BluetoothDevice#getName name} matching the given regular
+         * expression will be shown
          */
-        public Builder setNamePattern(@Nullable Pattern regex) {
+        @DataClass.Generated.Member
+        public @NonNull Builder setNamePattern(@Nullable Pattern value) {
             checkNotUsed();
-            mNamePattern = regex;
+            mBuilderFieldsSet |= 0x1;
+            mNamePattern = value;
             return this;
         }
 
-        /** @inheritDoc */
-        @Override
-        @NonNull
-        public WifiDeviceFilter build() {
-            markUsed();
-            return new WifiDeviceFilter(mNamePattern);
+        /**
+         * If set, only devices with BSSID matching the given one will be shown
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setBssid(@Nullable MacAddress value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            mBssid = value;
+            return this;
+        }
+
+        /**
+         * If set, only bits at positions set in this mask, will be compared to the given
+         * {@link Builder#setBssid BSSID} filter.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setBssidMask(@NonNull MacAddress value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4;
+            mBssidMask = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @NonNull WifiDeviceFilter build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x8; // Mark builder used
+
+            if ((mBuilderFieldsSet & 0x1) == 0) {
+                mNamePattern = null;
+            }
+            if ((mBuilderFieldsSet & 0x2) == 0) {
+                mBssid = null;
+            }
+            if ((mBuilderFieldsSet & 0x4) == 0) {
+                mBssidMask = MacAddress.BROADCAST_ADDRESS;
+            }
+            WifiDeviceFilter o = new WifiDeviceFilter(
+                    mNamePattern,
+                    mBssid,
+                    mBssidMask);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x8) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
         }
     }
+
+    @DataClass.Generated(
+            time = 1571960300742L,
+            codegenVersion = "1.0.11",
+            sourceFile = "frameworks/base/core/java/android/companion/WifiDeviceFilter.java",
+            inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.Nullable java.util.regex.Pattern mNamePattern\nprivate @android.annotation.Nullable android.net.MacAddress mBssid\nprivate @android.annotation.NonNull android.net.MacAddress mBssidMask\npublic @java.lang.Override boolean matches(android.net.wifi.ScanResult)\npublic @java.lang.Override java.lang.String getDeviceDisplayName(android.net.wifi.ScanResult)\npublic @java.lang.Override int getMediumType()\nclass WifiDeviceFilter extends java.lang.Object implements [android.companion.DeviceFilter<android.net.wifi.ScanResult>]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=false, genBuilder=true, genEqualsHashCode=true, genHiddenGetters=true)")
+    @Deprecated
+    private void __metadata() {}
+
 }
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index fdef2a1..b6a0a56 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -1069,9 +1069,8 @@
             if (!first) {
                 b.append(' ');
             }
-            mItems.get(0).toShortString(b);
-            if (mItems.size() > 1) {
-                b.append(" ...");
+            for (int i=0; i<mItems.size(); i++) {
+                b.append("{...}");
             }
         }
     }
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 02b6b3e..17f1a07 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -53,6 +53,7 @@
 import android.os.storage.StorageManager;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -136,7 +137,7 @@
     private boolean mNoPerms;
     private boolean mSingleUser;
 
-    private ThreadLocal<String> mCallingPackage;
+    private ThreadLocal<Pair<String, String>> mCallingPackage;
 
     private Transport mTransport = new Transport();
 
@@ -226,11 +227,13 @@
         }
 
         @Override
-        public Cursor query(String callingPkg, Uri uri, @Nullable String[] projection,
-                @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal) {
+        public Cursor query(String callingPkg, @Nullable String featureId, Uri uri,
+                @Nullable String[] projection, @Nullable Bundle queryArgs,
+                @Nullable ICancellationSignal cancellationSignal) {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceReadPermission(callingPkg, featureId, uri, null)
+                    != AppOpsManager.MODE_ALLOWED) {
                 // The caller has no access to the data, so return an empty cursor with
                 // the columns in the requested order. The caller may ask for an invalid
                 // column and we would not catch that but this is not a problem in practice.
@@ -246,7 +249,8 @@
                 // we have to execute the query as if allowed to get a cursor with the
                 // columns. We then use the column names to return an empty cursor.
                 Cursor cursor;
-                final String original = setCallingPackage(callingPkg);
+                final Pair<String, String> original = setCallingPackage(
+                        new Pair<>(callingPkg, featureId));
                 try {
                     cursor = mInterface.query(
                             uri, projection, queryArgs,
@@ -264,7 +268,8 @@
                 return new MatrixCursor(cursor.getColumnNames(), 0);
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "query");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return mInterface.query(
                         uri, projection, queryArgs,
@@ -293,12 +298,15 @@
         }
 
         @Override
-        public Uri insert(String callingPkg, Uri uri, ContentValues initialValues) {
+        public Uri insert(String callingPkg, @Nullable String featureId, Uri uri,
+                ContentValues initialValues) {
             uri = validateIncomingUri(uri);
             int userId = getUserIdFromUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
-                final String original = setCallingPackage(callingPkg);
+            if (enforceWritePermission(callingPkg, featureId, uri, null)
+                    != AppOpsManager.MODE_ALLOWED) {
+                final Pair<String, String> original = setCallingPackage(
+                        new Pair<>(callingPkg, featureId));
                 try {
                     return rejectInsert(uri, initialValues);
                 } finally {
@@ -306,7 +314,8 @@
                 }
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "insert");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return maybeAddUserId(mInterface.insert(uri, initialValues), userId);
             } catch (RemoteException e) {
@@ -318,14 +327,17 @@
         }
 
         @Override
-        public int bulkInsert(String callingPkg, Uri uri, ContentValues[] initialValues) {
+        public int bulkInsert(String callingPkg, @Nullable String featureId, Uri uri,
+                ContentValues[] initialValues) {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceWritePermission(callingPkg, featureId, uri, null)
+                    != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "bulkInsert");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return mInterface.bulkInsert(uri, initialValues);
             } catch (RemoteException e) {
@@ -337,8 +349,8 @@
         }
 
         @Override
-        public ContentProviderResult[] applyBatch(String callingPkg, String authority,
-                ArrayList<ContentProviderOperation> operations)
+        public ContentProviderResult[] applyBatch(String callingPkg, @Nullable String featureId,
+                String authority, ArrayList<ContentProviderOperation> operations)
                 throws OperationApplicationException {
             validateIncomingAuthority(authority);
             int numOperations = operations.size();
@@ -355,20 +367,21 @@
                     operations.set(i, operation);
                 }
                 if (operation.isReadOperation()) {
-                    if (enforceReadPermission(callingPkg, uri, null)
+                    if (enforceReadPermission(callingPkg, featureId, uri, null)
                             != AppOpsManager.MODE_ALLOWED) {
                         throw new OperationApplicationException("App op not allowed", 0);
                     }
                 }
                 if (operation.isWriteOperation()) {
-                    if (enforceWritePermission(callingPkg, uri, null)
+                    if (enforceWritePermission(callingPkg, featureId, uri, null)
                             != AppOpsManager.MODE_ALLOWED) {
                         throw new OperationApplicationException("App op not allowed", 0);
                     }
                 }
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "applyBatch");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 ContentProviderResult[] results = mInterface.applyBatch(authority,
                         operations);
@@ -390,14 +403,17 @@
         }
 
         @Override
-        public int delete(String callingPkg, Uri uri, String selection, String[] selectionArgs) {
+        public int delete(String callingPkg, @Nullable String featureId, Uri uri, String selection,
+                String[] selectionArgs) {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceWritePermission(callingPkg, featureId, uri, null)
+                    != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "delete");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return mInterface.delete(uri, selection, selectionArgs);
             } catch (RemoteException e) {
@@ -409,15 +425,17 @@
         }
 
         @Override
-        public int update(String callingPkg, Uri uri, ContentValues values, String selection,
-                String[] selectionArgs) {
+        public int update(String callingPkg, @Nullable String featureId, Uri uri,
+                ContentValues values, String selection, String[] selectionArgs) {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceWritePermission(callingPkg, featureId, uri, null)
+                    != AppOpsManager.MODE_ALLOWED) {
                 return 0;
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "update");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return mInterface.update(uri, values, selection, selectionArgs);
             } catch (RemoteException e) {
@@ -429,14 +447,15 @@
         }
 
         @Override
-        public ParcelFileDescriptor openFile(
-                String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal,
-                IBinder callerToken) throws FileNotFoundException {
+        public ParcelFileDescriptor openFile(String callingPkg, @Nullable String featureId,
+                Uri uri, String mode, ICancellationSignal cancellationSignal, IBinder callerToken)
+                throws FileNotFoundException {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            enforceFilePermission(callingPkg, uri, mode, callerToken);
+            enforceFilePermission(callingPkg, featureId, uri, mode, callerToken);
             Trace.traceBegin(TRACE_TAG_DATABASE, "openFile");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return mInterface.openFile(
                         uri, mode, CancellationSignal.fromTransport(cancellationSignal));
@@ -449,14 +468,15 @@
         }
 
         @Override
-        public AssetFileDescriptor openAssetFile(
-                String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
+        public AssetFileDescriptor openAssetFile(String callingPkg, @Nullable String featureId,
+                Uri uri, String mode, ICancellationSignal cancellationSignal)
                 throws FileNotFoundException {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            enforceFilePermission(callingPkg, uri, mode, null);
+            enforceFilePermission(callingPkg, featureId, uri, mode, null);
             Trace.traceBegin(TRACE_TAG_DATABASE, "openAssetFile");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return mInterface.openAssetFile(
                         uri, mode, CancellationSignal.fromTransport(cancellationSignal));
@@ -469,12 +489,13 @@
         }
 
         @Override
-        public Bundle call(String callingPkg, String authority, String method, @Nullable String arg,
-                @Nullable Bundle extras) {
+        public Bundle call(String callingPkg, @Nullable String featureId, String authority,
+                String method, @Nullable String arg, @Nullable Bundle extras) {
             validateIncomingAuthority(authority);
             Bundle.setDefusable(extras, true);
             Trace.traceBegin(TRACE_TAG_DATABASE, "call");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return mInterface.call(authority, method, arg, extras);
             } catch (RemoteException e) {
@@ -501,14 +522,16 @@
         }
 
         @Override
-        public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
-                Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
+        public AssetFileDescriptor openTypedAssetFile(String callingPkg,
+                @Nullable String featureId, Uri uri, String mimeType, Bundle opts,
+                ICancellationSignal cancellationSignal) throws FileNotFoundException {
             Bundle.setDefusable(opts, true);
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
-            enforceFilePermission(callingPkg, uri, "r", null);
+            enforceFilePermission(callingPkg, featureId, uri, "r", null);
             Trace.traceBegin(TRACE_TAG_DATABASE, "openTypedAssetFile");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return mInterface.openTypedAssetFile(
                         uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal));
@@ -526,15 +549,17 @@
         }
 
         @Override
-        public Uri canonicalize(String callingPkg, Uri uri) {
+        public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri) {
             uri = validateIncomingUri(uri);
             int userId = getUserIdFromUri(uri);
             uri = getUriWithoutUserId(uri);
-            if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceReadPermission(callingPkg, featureId, uri, null)
+                    != AppOpsManager.MODE_ALLOWED) {
                 return null;
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "canonicalize");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return maybeAddUserId(mInterface.canonicalize(uri), userId);
             } catch (RemoteException e) {
@@ -546,15 +571,17 @@
         }
 
         @Override
-        public Uri uncanonicalize(String callingPkg, Uri uri) {
+        public Uri uncanonicalize(String callingPkg, String featureId,  Uri uri) {
             uri = validateIncomingUri(uri);
             int userId = getUserIdFromUri(uri);
             uri = getUriWithoutUserId(uri);
-            if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceReadPermission(callingPkg, featureId, uri, null)
+                    != AppOpsManager.MODE_ALLOWED) {
                 return null;
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "uncanonicalize");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return maybeAddUserId(mInterface.uncanonicalize(uri), userId);
             } catch (RemoteException e) {
@@ -566,15 +593,17 @@
         }
 
         @Override
-        public boolean refresh(String callingPkg, Uri uri, Bundle args,
+        public boolean refresh(String callingPkg, String featureId, Uri uri, Bundle args,
                 ICancellationSignal cancellationSignal) throws RemoteException {
             uri = validateIncomingUri(uri);
             uri = getUriWithoutUserId(uri);
-            if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
+            if (enforceReadPermission(callingPkg, featureId, uri, null)
+                    != AppOpsManager.MODE_ALLOWED) {
                 return false;
             }
             Trace.traceBegin(TRACE_TAG_DATABASE, "refresh");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return mInterface.refresh(uri, args,
                         CancellationSignal.fromTransport(cancellationSignal));
@@ -585,11 +614,13 @@
         }
 
         @Override
-        public int checkUriPermission(String callingPkg, Uri uri, int uid, int modeFlags) {
+        public int checkUriPermission(String callingPkg, @Nullable String featureId, Uri uri,
+                int uid, int modeFlags) {
             uri = validateIncomingUri(uri);
             uri = maybeGetUriWithoutUserId(uri);
             Trace.traceBegin(TRACE_TAG_DATABASE, "checkUriPermission");
-            final String original = setCallingPackage(callingPkg);
+            final Pair<String, String> original = setCallingPackage(
+                    new Pair<>(callingPkg, featureId));
             try {
                 return mInterface.checkUriPermission(uri, uid, modeFlags);
             } catch (RemoteException e) {
@@ -600,44 +631,47 @@
             }
         }
 
-        private void enforceFilePermission(String callingPkg, Uri uri, String mode,
-                IBinder callerToken) throws FileNotFoundException, SecurityException {
+        private void enforceFilePermission(String callingPkg, @Nullable String featureId, Uri uri,
+                String mode, IBinder callerToken) throws FileNotFoundException, SecurityException {
             if (mode != null && mode.indexOf('w') != -1) {
-                if (enforceWritePermission(callingPkg, uri, callerToken)
+                if (enforceWritePermission(callingPkg, featureId, uri, callerToken)
                         != AppOpsManager.MODE_ALLOWED) {
                     throw new FileNotFoundException("App op not allowed");
                 }
             } else {
-                if (enforceReadPermission(callingPkg, uri, callerToken)
+                if (enforceReadPermission(callingPkg, featureId, uri, callerToken)
                         != AppOpsManager.MODE_ALLOWED) {
                     throw new FileNotFoundException("App op not allowed");
                 }
             }
         }
 
-        private int enforceReadPermission(String callingPkg, Uri uri, IBinder callerToken)
+        private int enforceReadPermission(String callingPkg, @Nullable String featureId, Uri uri,
+                IBinder callerToken)
                 throws SecurityException {
-            final int mode = enforceReadPermissionInner(uri, callingPkg, callerToken);
+            final int mode = enforceReadPermissionInner(uri, callingPkg, featureId, callerToken);
             if (mode != MODE_ALLOWED) {
                 return mode;
             }
 
-            return noteProxyOp(callingPkg, mReadOp);
+            return noteProxyOp(callingPkg, featureId, mReadOp);
         }
 
-        private int enforceWritePermission(String callingPkg, Uri uri, IBinder callerToken)
+        private int enforceWritePermission(String callingPkg, String featureId, Uri uri,
+                IBinder callerToken)
                 throws SecurityException {
-            final int mode = enforceWritePermissionInner(uri, callingPkg, callerToken);
+            final int mode = enforceWritePermissionInner(uri, callingPkg, featureId, callerToken);
             if (mode != MODE_ALLOWED) {
                 return mode;
             }
 
-            return noteProxyOp(callingPkg, mWriteOp);
+            return noteProxyOp(callingPkg, featureId, mWriteOp);
         }
 
-        private int noteProxyOp(String callingPkg, int op) {
+        private int noteProxyOp(String callingPkg, String featureId, int op) {
             if (op != AppOpsManager.OP_NONE) {
-                int mode = mAppOpsManager.noteProxyOp(op, callingPkg);
+                int mode = mAppOpsManager.noteProxyOp(op, callingPkg, Binder.getCallingUid(),
+                        featureId, null);
                 return mode == MODE_DEFAULT ? MODE_IGNORED : mode;
             }
 
@@ -659,18 +693,19 @@
      * associated with that permission.
      */
     private int checkPermissionAndAppOp(String permission, String callingPkg,
-            IBinder callerToken) {
+            @Nullable String featureId, IBinder callerToken) {
         if (getContext().checkPermission(permission, Binder.getCallingPid(), Binder.getCallingUid(),
                 callerToken) != PERMISSION_GRANTED) {
             return MODE_ERRORED;
         }
 
-        return mTransport.noteProxyOp(callingPkg, AppOpsManager.permissionToOpCode(permission));
+        return mTransport.noteProxyOp(callingPkg, featureId,
+                AppOpsManager.permissionToOpCode(permission));
     }
 
     /** {@hide} */
-    protected int enforceReadPermissionInner(Uri uri, String callingPkg, IBinder callerToken)
-            throws SecurityException {
+    protected int enforceReadPermissionInner(Uri uri, String callingPkg,
+            @Nullable String featureId, IBinder callerToken) throws SecurityException {
         final Context context = getContext();
         final int pid = Binder.getCallingPid();
         final int uid = Binder.getCallingUid();
@@ -684,7 +719,8 @@
         if (mExported && checkUser(pid, uid, context)) {
             final String componentPerm = getReadPermission();
             if (componentPerm != null) {
-                final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, callerToken);
+                final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, featureId,
+                        callerToken);
                 if (mode == MODE_ALLOWED) {
                     return MODE_ALLOWED;
                 } else {
@@ -703,7 +739,8 @@
                 for (PathPermission pp : pps) {
                     final String pathPerm = pp.getReadPermission();
                     if (pathPerm != null && pp.match(path)) {
-                        final int mode = checkPermissionAndAppOp(pathPerm, callingPkg, callerToken);
+                        final int mode = checkPermissionAndAppOp(pathPerm, callingPkg, featureId,
+                                callerToken);
                         if (mode == MODE_ALLOWED) {
                             return MODE_ALLOWED;
                         } else {
@@ -751,8 +788,8 @@
     }
 
     /** {@hide} */
-    protected int enforceWritePermissionInner(Uri uri, String callingPkg, IBinder callerToken)
-            throws SecurityException {
+    protected int enforceWritePermissionInner(Uri uri, String callingPkg,
+            @Nullable String featureId, IBinder callerToken) throws SecurityException {
         final Context context = getContext();
         final int pid = Binder.getCallingPid();
         final int uid = Binder.getCallingUid();
@@ -766,7 +803,8 @@
         if (mExported && checkUser(pid, uid, context)) {
             final String componentPerm = getWritePermission();
             if (componentPerm != null) {
-                final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, callerToken);
+                final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, featureId,
+                        callerToken);
                 if (mode == MODE_ALLOWED) {
                     return MODE_ALLOWED;
                 } else {
@@ -785,7 +823,8 @@
                 for (PathPermission pp : pps) {
                     final String pathPerm = pp.getWritePermission();
                     if (pathPerm != null && pp.match(path)) {
-                        final int mode = checkPermissionAndAppOp(pathPerm, callingPkg, callerToken);
+                        final int mode = checkPermissionAndAppOp(pathPerm, callingPkg, featureId,
+                                callerToken);
                         if (mode == MODE_ALLOWED) {
                             return MODE_ALLOWED;
                         } else {
@@ -834,11 +873,28 @@
     }
 
     /**
-     * Set the calling package, returning the current value (or {@code null})
+     * Retrieves a Non-Nullable Context this provider is running in, this is intended to be called
+     * after {@link #onCreate}. When called before context was created, an IllegalStateException
+     * will be thrown.
+     * <p>
+     * Note A provider must be declared in the manifest and created automatically by the system,
+     * and context is only available after {@link #onCreate} is called.
+     */
+    @NonNull
+    public final Context requireContext() {
+        final Context ctx = getContext();
+        if (ctx == null) {
+            throw new IllegalStateException("Cannot find context from the provider.");
+        }
+        return ctx;
+    }
+
+    /**
+     * Set the calling package/feature, returning the current value (or {@code null})
      * which can be used later to restore the previous state.
      */
-    private String setCallingPackage(String callingPackage) {
-        final String original = mCallingPackage.get();
+    private Pair<String, String> setCallingPackage(Pair<String, String> callingPackage) {
+        final Pair<String, String> original = mCallingPackage.get();
         mCallingPackage.set(callingPackage);
         onCallingPackageChanged();
         return original;
@@ -859,16 +915,42 @@
      *             calling UID.
      */
     public final @Nullable String getCallingPackage() {
-        final String pkg = mCallingPackage.get();
+        final Pair<String, String> pkg = mCallingPackage.get();
         if (pkg != null) {
-            mTransport.mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg);
+            mTransport.mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg.first);
+            return pkg.first;
         }
-        return pkg;
+
+        return null;
+    }
+
+    /**
+     * Return the feature in the package of the caller that initiated the request being
+     * processed on the current thread. Returns {@code null} if not currently processing
+     * a request of the request is for the default feature.
+     * <p>
+     * This will always return {@code null} when processing
+     * {@link #getType(Uri)} or {@link #getStreamTypes(Uri, String)} requests.
+     *
+     * @see #getCallingPackage
+     */
+    public final @Nullable String getCallingFeatureId() {
+        final Pair<String, String> pkg = mCallingPackage.get();
+        if (pkg != null) {
+            return pkg.second;
+        }
+
+        return null;
     }
 
     /** {@hide} */
     public final @Nullable String getCallingPackageUnchecked() {
-        return mCallingPackage.get();
+        final Pair<String, String> pkg = mCallingPackage.get();
+        if (pkg != null) {
+            return pkg.first;
+        }
+
+        return null;
     }
 
     /** {@hide} */
@@ -882,10 +964,10 @@
         /** {@hide} */
         public final long binderToken;
         /** {@hide} */
-        public final String callingPackage;
+        public final Pair<String, String> callingPackage;
 
         /** {@hide} */
-        public CallingIdentity(long binderToken, String callingPackage) {
+        public CallingIdentity(long binderToken, Pair<String, String> callingPackage) {
             this.binderToken = binderToken;
             this.callingPackage = callingPackage;
         }
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index 8a4330e..d2632e7 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -80,6 +80,7 @@
     private final IContentProvider mContentProvider;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final String mPackageName;
+    private final @Nullable String mFeatureId;
     private final String mAuthority;
     private final boolean mStable;
 
@@ -103,6 +104,7 @@
         mContentResolver = contentResolver;
         mContentProvider = contentProvider;
         mPackageName = contentResolver.mPackageName;
+        mFeatureId = contentResolver.mFeatureId;
 
         mAuthority = authority;
         mStable = stable;
@@ -193,7 +195,7 @@
                 cancellationSignal.setRemote(remoteCancellationSignal);
             }
             final Cursor cursor = mContentProvider.query(
-                    mPackageName, uri, projection, queryArgs, remoteCancellationSignal);
+                    mPackageName, mFeatureId, uri, projection, queryArgs, remoteCancellationSignal);
             if (cursor == null) {
                 return null;
             }
@@ -253,7 +255,7 @@
 
         beforeRemote();
         try {
-            return mContentProvider.canonicalize(mPackageName, url);
+            return mContentProvider.canonicalize(mPackageName, mFeatureId, url);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -271,7 +273,7 @@
 
         beforeRemote();
         try {
-            return mContentProvider.uncanonicalize(mPackageName, url);
+            return mContentProvider.uncanonicalize(mPackageName, mFeatureId, url);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -296,7 +298,8 @@
                 remoteCancellationSignal = mContentProvider.createCancellationSignal();
                 cancellationSignal.setRemote(remoteCancellationSignal);
             }
-            return mContentProvider.refresh(mPackageName, url, args, remoteCancellationSignal);
+            return mContentProvider.refresh(mPackageName, mFeatureId, url, args,
+                    remoteCancellationSignal);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -315,7 +318,8 @@
 
         beforeRemote();
         try {
-            return mContentProvider.checkUriPermission(mPackageName, uri, uid, modeFlags);
+            return mContentProvider.checkUriPermission(mPackageName, mFeatureId, uri, uid,
+                    modeFlags);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -334,7 +338,7 @@
 
         beforeRemote();
         try {
-            return mContentProvider.insert(mPackageName, url, initialValues);
+            return mContentProvider.insert(mPackageName, mFeatureId, url, initialValues);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -354,7 +358,7 @@
 
         beforeRemote();
         try {
-            return mContentProvider.bulkInsert(mPackageName, url, initialValues);
+            return mContentProvider.bulkInsert(mPackageName, mFeatureId, url, initialValues);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -373,7 +377,8 @@
 
         beforeRemote();
         try {
-            return mContentProvider.delete(mPackageName, url, selection, selectionArgs);
+            return mContentProvider.delete(mPackageName, mFeatureId, url, selection,
+                    selectionArgs);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -392,7 +397,8 @@
 
         beforeRemote();
         try {
-            return mContentProvider.update(mPackageName, url, values, selection, selectionArgs);
+            return mContentProvider.update(mPackageName, mFeatureId, url, values, selection,
+                    selectionArgs);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -436,7 +442,8 @@
                 remoteSignal = mContentProvider.createCancellationSignal();
                 signal.setRemote(remoteSignal);
             }
-            return mContentProvider.openFile(mPackageName, url, mode, remoteSignal, null);
+            return mContentProvider.openFile(mPackageName, mFeatureId, url, mode, remoteSignal,
+                    null);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -480,7 +487,8 @@
                 remoteSignal = mContentProvider.createCancellationSignal();
                 signal.setRemote(remoteSignal);
             }
-            return mContentProvider.openAssetFile(mPackageName, url, mode, remoteSignal);
+            return mContentProvider.openAssetFile(mPackageName, mFeatureId, url, mode,
+                    remoteSignal);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -521,7 +529,7 @@
                 signal.setRemote(remoteSignal);
             }
             return mContentProvider.openTypedAssetFile(
-                    mPackageName, uri, mimeTypeFilter, opts, remoteSignal);
+                    mPackageName, mFeatureId, uri, mimeTypeFilter, opts, remoteSignal);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -548,7 +556,7 @@
 
         beforeRemote();
         try {
-            return mContentProvider.applyBatch(mPackageName, authority, operations);
+            return mContentProvider.applyBatch(mPackageName, mFeatureId, authority, operations);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -574,7 +582,7 @@
 
         beforeRemote();
         try {
-            return mContentProvider.call(mPackageName, authority, method, arg, extras);
+            return mContentProvider.call(mPackageName, mFeatureId, authority, method, arg, extras);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index cd735d4..f082690 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -83,6 +83,7 @@
                     data.enforceInterface(IContentProvider.descriptor);
 
                     String callingPkg = data.readString();
+                    String callingFeatureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
 
                     // String[] projection
@@ -101,7 +102,8 @@
                     ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
                             data.readStrongBinder());
 
-                    Cursor cursor = query(callingPkg, url, projection, queryArgs, cancellationSignal);
+                    Cursor cursor = query(callingPkg, callingFeatureId, url, projection, queryArgs,
+                            cancellationSignal);
                     if (cursor != null) {
                         CursorToBulkCursorAdaptor adaptor = null;
 
@@ -148,10 +150,11 @@
                 {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     ContentValues values = ContentValues.CREATOR.createFromParcel(data);
 
-                    Uri out = insert(callingPkg, url, values);
+                    Uri out = insert(callingPkg, featureId, url, values);
                     reply.writeNoException();
                     Uri.writeToParcel(reply, out);
                     return true;
@@ -161,10 +164,11 @@
                 {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     ContentValues[] values = data.createTypedArray(ContentValues.CREATOR);
 
-                    int count = bulkInsert(callingPkg, url, values);
+                    int count = bulkInsert(callingPkg, featureId, url, values);
                     reply.writeNoException();
                     reply.writeInt(count);
                     return true;
@@ -174,6 +178,7 @@
                 {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     String authority = data.readString();
                     final int numOperations = data.readInt();
                     final ArrayList<ContentProviderOperation> operations =
@@ -181,8 +186,8 @@
                     for (int i = 0; i < numOperations; i++) {
                         operations.add(i, ContentProviderOperation.CREATOR.createFromParcel(data));
                     }
-                    final ContentProviderResult[] results = applyBatch(callingPkg, authority,
-                            operations);
+                    final ContentProviderResult[] results = applyBatch(callingPkg, featureId,
+                            authority, operations);
                     reply.writeNoException();
                     reply.writeTypedArray(results, 0);
                     return true;
@@ -192,11 +197,12 @@
                 {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     String selection = data.readString();
                     String[] selectionArgs = data.readStringArray();
 
-                    int count = delete(callingPkg, url, selection, selectionArgs);
+                    int count = delete(callingPkg, featureId, url, selection, selectionArgs);
 
                     reply.writeNoException();
                     reply.writeInt(count);
@@ -207,12 +213,14 @@
                 {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     ContentValues values = ContentValues.CREATOR.createFromParcel(data);
                     String selection = data.readString();
                     String[] selectionArgs = data.readStringArray();
 
-                    int count = update(callingPkg, url, values, selection, selectionArgs);
+                    int count = update(callingPkg, featureId, url, values, selection,
+                            selectionArgs);
 
                     reply.writeNoException();
                     reply.writeInt(count);
@@ -223,6 +231,7 @@
                 {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     String mode = data.readString();
                     ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
@@ -230,7 +239,7 @@
                     IBinder callerToken = data.readStrongBinder();
 
                     ParcelFileDescriptor fd;
-                    fd = openFile(callingPkg, url, mode, signal, callerToken);
+                    fd = openFile(callingPkg, featureId, url, mode, signal, callerToken);
                     reply.writeNoException();
                     if (fd != null) {
                         reply.writeInt(1);
@@ -246,13 +255,14 @@
                 {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     String mode = data.readString();
                     ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
                             data.readStrongBinder());
 
                     AssetFileDescriptor fd;
-                    fd = openAssetFile(callingPkg, url, mode, signal);
+                    fd = openAssetFile(callingPkg, featureId, url, mode, signal);
                     reply.writeNoException();
                     if (fd != null) {
                         reply.writeInt(1);
@@ -269,12 +279,14 @@
                     data.enforceInterface(IContentProvider.descriptor);
 
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     String authority = data.readString();
                     String method = data.readString();
                     String stringArg = data.readString();
                     Bundle args = data.readBundle();
 
-                    Bundle responseBundle = call(callingPkg, authority, method, stringArg, args);
+                    Bundle responseBundle = call(callingPkg, featureId, authority, method,
+                            stringArg, args);
 
                     reply.writeNoException();
                     reply.writeBundle(responseBundle);
@@ -297,6 +309,7 @@
                 {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     String mimeType = data.readString();
                     Bundle opts = data.readBundle();
@@ -304,7 +317,7 @@
                             data.readStrongBinder());
 
                     AssetFileDescriptor fd;
-                    fd = openTypedAssetFile(callingPkg, url, mimeType, opts, signal);
+                    fd = openTypedAssetFile(callingPkg, featureId, url, mimeType, opts, signal);
                     reply.writeNoException();
                     if (fd != null) {
                         reply.writeInt(1);
@@ -330,9 +343,10 @@
                 {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
 
-                    Uri out = canonicalize(callingPkg, url);
+                    Uri out = canonicalize(callingPkg, featureId, url);
                     reply.writeNoException();
                     Uri.writeToParcel(reply, out);
                     return true;
@@ -342,9 +356,10 @@
                 {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
 
-                    Uri out = uncanonicalize(callingPkg, url);
+                    Uri out = uncanonicalize(callingPkg, featureId, url);
                     reply.writeNoException();
                     Uri.writeToParcel(reply, out);
                     return true;
@@ -353,12 +368,13 @@
                 case REFRESH_TRANSACTION: {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri url = Uri.CREATOR.createFromParcel(data);
                     Bundle args = data.readBundle();
                     ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
                             data.readStrongBinder());
 
-                    boolean out = refresh(callingPkg, url, args, signal);
+                    boolean out = refresh(callingPkg, featureId, url, args, signal);
                     reply.writeNoException();
                     reply.writeInt(out ? 0 : -1);
                     return true;
@@ -367,11 +383,12 @@
                 case CHECK_URI_PERMISSION_TRANSACTION: {
                     data.enforceInterface(IContentProvider.descriptor);
                     String callingPkg = data.readString();
+                    String featureId = data.readString();
                     Uri uri = Uri.CREATOR.createFromParcel(data);
                     int uid = data.readInt();
                     int modeFlags = data.readInt();
 
-                    int out = checkUriPermission(callingPkg, uri, uid, modeFlags);
+                    int out = checkUriPermission(callingPkg, featureId, uri, uid, modeFlags);
                     reply.writeNoException();
                     reply.writeInt(out);
                     return true;
@@ -407,8 +424,9 @@
     }
 
     @Override
-    public Cursor query(String callingPkg, Uri url, @Nullable String[] projection,
-            @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal)
+    public Cursor query(String callingPkg, @Nullable String featureId, Uri url,
+            @Nullable String[] projection, @Nullable Bundle queryArgs,
+            @Nullable ICancellationSignal cancellationSignal)
             throws RemoteException {
         BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
         Parcel data = Parcel.obtain();
@@ -417,6 +435,7 @@
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
             int length = 0;
             if (projection != null) {
@@ -478,7 +497,8 @@
     }
 
     @Override
-    public Uri insert(String callingPkg, Uri url, ContentValues values) throws RemoteException
+    public Uri insert(String callingPkg, @Nullable String featureId, Uri url,
+            ContentValues values) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -486,6 +506,7 @@
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
             values.writeToParcel(data, 0);
 
@@ -501,13 +522,15 @@
     }
 
     @Override
-    public int bulkInsert(String callingPkg, Uri url, ContentValues[] values) throws RemoteException {
+    public int bulkInsert(String callingPkg, @Nullable String featureId, Uri url,
+            ContentValues[] values) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
             data.writeTypedArray(values, 0);
 
@@ -523,14 +546,15 @@
     }
 
     @Override
-    public ContentProviderResult[] applyBatch(String callingPkg, String authority,
-            ArrayList<ContentProviderOperation> operations)
-                    throws RemoteException, OperationApplicationException {
+    public ContentProviderResult[] applyBatch(String callingPkg, @Nullable String featureId,
+            String authority, ArrayList<ContentProviderOperation> operations)
+            throws RemoteException, OperationApplicationException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
             data.writeInterfaceToken(IContentProvider.descriptor);
             data.writeString(callingPkg);
+            data.writeString(featureId);
             data.writeString(authority);
             data.writeInt(operations.size());
             for (ContentProviderOperation operation : operations) {
@@ -549,14 +573,15 @@
     }
 
     @Override
-    public int delete(String callingPkg, Uri url, String selection, String[] selectionArgs)
-            throws RemoteException {
+    public int delete(String callingPkg, @Nullable String featureId, Uri url, String selection,
+            String[] selectionArgs) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
             data.writeString(selection);
             data.writeStringArray(selectionArgs);
@@ -573,14 +598,15 @@
     }
 
     @Override
-    public int update(String callingPkg, Uri url, ContentValues values, String selection,
-            String[] selectionArgs) throws RemoteException {
+    public int update(String callingPkg, @Nullable String featureId, Uri url,
+            ContentValues values, String selection, String[] selectionArgs) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
             values.writeToParcel(data, 0);
             data.writeString(selection);
@@ -598,8 +624,8 @@
     }
 
     @Override
-    public ParcelFileDescriptor openFile(
-            String callingPkg, Uri url, String mode, ICancellationSignal signal, IBinder token)
+    public ParcelFileDescriptor openFile(String callingPkg, @Nullable String featureId, Uri url,
+            String mode, ICancellationSignal signal, IBinder token)
             throws RemoteException, FileNotFoundException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -607,6 +633,7 @@
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
             data.writeString(mode);
             data.writeStrongBinder(signal != null ? signal.asBinder() : null);
@@ -626,8 +653,8 @@
     }
 
     @Override
-    public AssetFileDescriptor openAssetFile(
-            String callingPkg, Uri url, String mode, ICancellationSignal signal)
+    public AssetFileDescriptor openAssetFile(String callingPkg, @Nullable String featureId,
+            Uri url, String mode, ICancellationSignal signal)
             throws RemoteException, FileNotFoundException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -635,6 +662,7 @@
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
             data.writeString(mode);
             data.writeStrongBinder(signal != null ? signal.asBinder() : null);
@@ -653,14 +681,15 @@
     }
 
     @Override
-    public Bundle call(String callingPkg, String authority, String method, String request,
-            Bundle args) throws RemoteException {
+    public Bundle call(String callingPkg, @Nullable String featureId, String authority,
+            String method, String request, Bundle args) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             data.writeString(authority);
             data.writeString(method);
             data.writeString(request);
@@ -700,14 +729,16 @@
     }
 
     @Override
-    public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri url, String mimeType,
-            Bundle opts, ICancellationSignal signal) throws RemoteException, FileNotFoundException {
+    public AssetFileDescriptor openTypedAssetFile(String callingPkg, @Nullable String featureId,
+            Uri url, String mimeType, Bundle opts, ICancellationSignal signal)
+            throws RemoteException, FileNotFoundException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
             data.writeString(mimeType);
             data.writeBundle(opts);
@@ -747,14 +778,15 @@
     }
 
     @Override
-    public Uri canonicalize(String callingPkg, Uri url) throws RemoteException
-    {
+    public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri url)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
 
             mRemote.transact(IContentProvider.CANONICALIZE_TRANSACTION, data, reply, 0);
@@ -769,13 +801,15 @@
     }
 
     @Override
-    public Uri uncanonicalize(String callingPkg, Uri url) throws RemoteException {
+    public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri url)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
 
             mRemote.transact(IContentProvider.UNCANONICALIZE_TRANSACTION, data, reply, 0);
@@ -790,14 +824,15 @@
     }
 
     @Override
-    public boolean refresh(String callingPkg, Uri url, Bundle args, ICancellationSignal signal)
-            throws RemoteException {
+    public boolean refresh(String callingPkg, @Nullable String featureId, Uri url, Bundle args,
+            ICancellationSignal signal) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
             data.writeBundle(args);
             data.writeStrongBinder(signal != null ? signal.asBinder() : null);
@@ -814,14 +849,15 @@
     }
 
     @Override
-    public int checkUriPermission(String callingPkg, Uri url, int uid, int modeFlags)
-            throws RemoteException {
+    public int checkUriPermission(String callingPkg, @Nullable String featureId, Uri url, int uid,
+            int modeFlags) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
             data.writeInterfaceToken(IContentProvider.descriptor);
 
             data.writeString(callingPkg);
+            data.writeString(featureId);
             url.writeToParcel(data, 0);
             data.writeInt(uid);
             data.writeInt(modeFlags);
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 7f9ea76..2657cc5 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -649,6 +649,7 @@
     public ContentResolver(@Nullable Context context, @Nullable ContentInterface wrapped) {
         mContext = context != null ? context : ActivityThread.currentApplication();
         mPackageName = mContext.getOpPackageName();
+        mFeatureId = mContext.getFeatureId();
         mTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
         mWrapped = wrapped;
     }
@@ -968,7 +969,7 @@
                 cancellationSignal.setRemote(remoteCancellationSignal);
             }
             try {
-                qCursor = unstableProvider.query(mPackageName, uri, projection,
+                qCursor = unstableProvider.query(mPackageName, mFeatureId, uri, projection,
                         queryArgs, remoteCancellationSignal);
             } catch (DeadObjectException e) {
                 // The remote process has died...  but we only hold an unstable
@@ -979,8 +980,8 @@
                 if (stableProvider == null) {
                     return null;
                 }
-                qCursor = stableProvider.query(
-                        mPackageName, uri, projection, queryArgs, remoteCancellationSignal);
+                qCursor = stableProvider.query(mPackageName, mFeatureId, uri, projection,
+                        queryArgs, remoteCancellationSignal);
             }
             if (qCursor == null) {
                 return null;
@@ -1070,7 +1071,7 @@
         }
 
         try {
-            return provider.canonicalize(mPackageName, url);
+            return provider.canonicalize(mPackageName, mFeatureId, url);
         } catch (RemoteException e) {
             // Arbitrary and not worth documenting, as Activity
             // Manager will kill this process shortly anyway.
@@ -1114,7 +1115,7 @@
         }
 
         try {
-            return provider.uncanonicalize(mPackageName, url);
+            return provider.uncanonicalize(mPackageName, mFeatureId, url);
         } catch (RemoteException e) {
             // Arbitrary and not worth documenting, as Activity
             // Manager will kill this process shortly anyway.
@@ -1163,7 +1164,8 @@
                 remoteCancellationSignal = provider.createCancellationSignal();
                 cancellationSignal.setRemote(remoteCancellationSignal);
             }
-            return provider.refresh(mPackageName, url, args, remoteCancellationSignal);
+            return provider.refresh(mPackageName, mFeatureId, url, args,
+                    remoteCancellationSignal);
         } catch (RemoteException e) {
             // Arbitrary and not worth documenting, as Activity
             // Manager will kill this process shortly anyway.
@@ -1564,7 +1566,7 @@
 
                     try {
                         fd = unstableProvider.openAssetFile(
-                                mPackageName, uri, mode, remoteCancellationSignal);
+                                mPackageName, mFeatureId, uri, mode, remoteCancellationSignal);
                         if (fd == null) {
                             // The provider will be released by the finally{} clause
                             return null;
@@ -1579,7 +1581,7 @@
                             throw new FileNotFoundException("No content provider: " + uri);
                         }
                         fd = stableProvider.openAssetFile(
-                                mPackageName, uri, mode, remoteCancellationSignal);
+                                mPackageName, mFeatureId, uri, mode, remoteCancellationSignal);
                         if (fd == null) {
                             // The provider will be released by the finally{} clause
                             return null;
@@ -1730,7 +1732,7 @@
 
             try {
                 fd = unstableProvider.openTypedAssetFile(
-                        mPackageName, uri, mimeType, opts, remoteCancellationSignal);
+                        mPackageName, mFeatureId, uri, mimeType, opts, remoteCancellationSignal);
                 if (fd == null) {
                     // The provider will be released by the finally{} clause
                     return null;
@@ -1745,7 +1747,7 @@
                     throw new FileNotFoundException("No content provider: " + uri);
                 }
                 fd = stableProvider.openTypedAssetFile(
-                        mPackageName, uri, mimeType, opts, remoteCancellationSignal);
+                        mPackageName, mFeatureId, uri, mimeType, opts, remoteCancellationSignal);
                 if (fd == null) {
                     // The provider will be released by the finally{} clause
                     return null;
@@ -1870,7 +1872,7 @@
         }
         try {
             long startTime = SystemClock.uptimeMillis();
-            Uri createdRow = provider.insert(mPackageName, url, values);
+            Uri createdRow = provider.insert(mPackageName, mFeatureId, url, values);
             long durationMillis = SystemClock.uptimeMillis() - startTime;
             maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */);
             return createdRow;
@@ -1951,7 +1953,7 @@
         }
         try {
             long startTime = SystemClock.uptimeMillis();
-            int rowsCreated = provider.bulkInsert(mPackageName, url, values);
+            int rowsCreated = provider.bulkInsert(mPackageName, mFeatureId, url, values);
             long durationMillis = SystemClock.uptimeMillis() - startTime;
             maybeLogUpdateToEventLog(durationMillis, url, "bulkinsert", null /* where */);
             return rowsCreated;
@@ -1991,7 +1993,8 @@
         }
         try {
             long startTime = SystemClock.uptimeMillis();
-            int rowsDeleted = provider.delete(mPackageName, url, where, selectionArgs);
+            int rowsDeleted = provider.delete(mPackageName, mFeatureId, url, where,
+                    selectionArgs);
             long durationMillis = SystemClock.uptimeMillis() - startTime;
             maybeLogUpdateToEventLog(durationMillis, url, "delete", where);
             return rowsDeleted;
@@ -2035,7 +2038,8 @@
         }
         try {
             long startTime = SystemClock.uptimeMillis();
-            int rowsUpdated = provider.update(mPackageName, uri, values, where, selectionArgs);
+            int rowsUpdated = provider.update(mPackageName, mFeatureId, uri, values, where,
+                    selectionArgs);
             long durationMillis = SystemClock.uptimeMillis() - startTime;
             maybeLogUpdateToEventLog(durationMillis, uri, "update", where);
             return rowsUpdated;
@@ -2084,7 +2088,8 @@
             throw new IllegalArgumentException("Unknown authority " + authority);
         }
         try {
-            final Bundle res = provider.call(mPackageName, authority, method, arg, extras);
+            final Bundle res = provider.call(mPackageName, mFeatureId, authority, method, arg,
+                    extras);
             Bundle.setDefusable(res, true);
             return res;
         } catch (RemoteException e) {
@@ -3436,6 +3441,11 @@
         return mPackageName;
     }
 
+    /** @hide */
+    public @Nullable String getFeatureId() {
+        return mFeatureId;
+    }
+
     @UnsupportedAppUsage
     private static volatile IContentService sContentService;
     @UnsupportedAppUsage
@@ -3443,6 +3453,7 @@
 
     @UnsupportedAppUsage
     final String mPackageName;
+    final @Nullable String mFeatureId;
     final int mTargetSdkVersion;
     final ContentInterface mWrapped;
 
@@ -3638,19 +3649,19 @@
             orientation.value = (extras != null) ? extras.getInt(EXTRA_ORIENTATION, 0) : 0;
             return afd;
         }), (ImageDecoder decoder, ImageInfo info, Source source) -> {
-            decoder.setAllocator(allocator);
+                decoder.setAllocator(allocator);
 
-            // One last-ditch check to see if we've been canceled.
-            if (signal != null) signal.throwIfCanceled();
+                // One last-ditch check to see if we've been canceled.
+                if (signal != null) signal.throwIfCanceled();
 
-            // We requested a rough thumbnail size, but the remote size may have
-            // returned something giant, so defensively scale down as needed.
-            final int widthSample = info.getSize().getWidth() / size.getWidth();
-            final int heightSample = info.getSize().getHeight() / size.getHeight();
-            final int sample = Math.min(widthSample, heightSample);
-            if (sample > 1) {
-                decoder.setTargetSampleSize(sample);
-            }
+                // We requested a rough thumbnail size, but the remote size may have
+                // returned something giant, so defensively scale down as needed.
+                final int widthSample = info.getSize().getWidth() / size.getWidth();
+                final int heightSample = info.getSize().getHeight() / size.getHeight();
+                final int sample = Math.max(widthSample, heightSample);
+                if (sample > 1) {
+                    decoder.setTargetSampleSize(sample);
+                }
         });
 
         // Transform the bitmap if requested. We use a side-channel to
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 9a9fc89..862ec50 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2417,6 +2417,44 @@
             @Nullable String initialData, @Nullable  Bundle initialExtras);
 
     /**
+     * Version of
+     * {@link #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String,
+     * Bundle)} that allows you to specify the App Op to enforce restrictions on which receivers
+     * the broadcast will be sent to.
+     *
+     * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
+     *
+     * @param intent The Intent to broadcast; all receivers matching this
+     *               Intent will receive the broadcast.
+     * @param receiverPermission String naming a permissions that
+     *               a receiver must hold in order to receive your broadcast.
+     *               If null, no permission is required.
+     * @param receiverAppOp The app op associated with the broadcast. If null, no appOp is
+     *                      required. If both receiverAppOp and receiverPermission are non-null,
+     *                      a receiver must have both of them to
+     *                      receive the broadcast
+     * @param resultReceiver Your own BroadcastReceiver to treat as the final
+     *                       receiver of the broadcast.
+     * @param scheduler A custom Handler with which to schedule the
+     *                  resultReceiver callback; if null it will be
+     *                  scheduled in the Context's main thread.
+     * @param initialCode An initial value for the result code.  Often
+     *                    Activity.RESULT_OK.
+     * @param initialData An initial value for the result data.  Often
+     *                    null.
+     * @param initialExtras An initial value for the result extras.  Often
+     *                      null.
+     *
+     * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
+     */
+    public void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent,
+            @Nullable String receiverPermission, @Nullable String receiverAppOp,
+            @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler,
+            int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
      * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
      * Intent you are sending stays around after the broadcast is complete,
      * so that others can quickly retrieve that data through the return
@@ -4745,6 +4783,14 @@
     public static final String TELEPHONY_REGISTRY_SERVICE = "telephony_registry";
 
     /**
+     * Use with {@link #getSystemService(String)} to retrieve an
+     * {@link android.os.BatteryStatsManager}.
+     * @hide
+     */
+    @SystemApi
+    public static final String BATTERY_STATS_SERVICE = "batterystats";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index d5d0dce..6174018 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -16,7 +16,9 @@
 
 package android.content;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
@@ -62,12 +64,12 @@
     public ContextWrapper(Context base) {
         mBase = base;
     }
-    
+
     /**
      * Set the base context for this ContextWrapper.  All calls will then be
      * delegated to the base context.  Throws
      * IllegalStateException if a base context has already been set.
-     * 
+     *
      * @param base The new base context for this wrapper.
      */
     protected void attachBaseContext(Context base) {
@@ -118,7 +120,7 @@
     public Context getApplicationContext() {
         return mBase.getApplicationContext();
     }
-    
+
     @Override
     public void setTheme(int resid) {
         mBase.setTheme(resid);
@@ -169,7 +171,7 @@
     public ApplicationInfo getApplicationInfo() {
         return mBase.getApplicationInfo();
     }
-    
+
     @Override
     public String getPackageResourcePath() {
         return mBase.getPackageResourcePath();
@@ -209,13 +211,13 @@
 
     @Override
     public FileInputStream openFileInput(String name)
-        throws FileNotFoundException {
+            throws FileNotFoundException {
         return mBase.openFileInput(name);
     }
 
     @Override
     public FileOutputStream openFileOutput(String name, int mode)
-        throws FileNotFoundException {
+            throws FileNotFoundException {
         return mBase.openFileOutput(name, mode);
     }
 
@@ -449,7 +451,7 @@
         mBase.startIntentSender(intent, fillInIntent, flagsMask,
                 flagsValues, extraFlags, options);
     }
-    
+
     @Override
     public void sendBroadcast(Intent intent) {
         mBase.sendBroadcast(intent);
@@ -494,9 +496,9 @@
 
     @Override
     public void sendOrderedBroadcast(
-        Intent intent, String receiverPermission, BroadcastReceiver resultReceiver,
-        Handler scheduler, int initialCode, String initialData,
-        Bundle initialExtras) {
+            Intent intent, String receiverPermission, BroadcastReceiver resultReceiver,
+            Handler scheduler, int initialCode, String initialData,
+            Bundle initialExtras) {
         mBase.sendOrderedBroadcast(intent, receiverPermission,
                 resultReceiver, scheduler, initialCode,
                 initialData, initialExtras);
@@ -506,7 +508,8 @@
     @SystemApi
     @Override
     public void sendOrderedBroadcast(
-            Intent intent, String receiverPermission, Bundle options, BroadcastReceiver resultReceiver,
+            Intent intent, String receiverPermission, Bundle options,
+            BroadcastReceiver resultReceiver,
             Handler scheduler, int initialCode, String initialData,
             Bundle initialExtras) {
         mBase.sendOrderedBroadcast(intent, receiverPermission,
@@ -517,9 +520,9 @@
     /** @hide */
     @Override
     public void sendOrderedBroadcast(
-        Intent intent, String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
-        Handler scheduler, int initialCode, String initialData,
-        Bundle initialExtras) {
+            Intent intent, String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+            Handler scheduler, int initialCode, String initialData,
+            Bundle initialExtras) {
         mBase.sendOrderedBroadcast(intent, receiverPermission, appOp,
                 resultReceiver, scheduler, initialCode,
                 initialData, initialExtras);
@@ -577,6 +580,15 @@
     }
 
     @Override
+    public void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent,
+            @Nullable String receiverPermission, @Nullable String receiverAppOp,
+            @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler,
+            int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras) {
+        mBase.sendOrderedBroadcast(intent, receiverPermission, receiverAppOp, resultReceiver,
+                scheduler, initialCode, initialData, initialExtras);
+    }
+
+    @Override
     @Deprecated
     public void sendStickyBroadcast(Intent intent) {
         mBase.sendStickyBroadcast(intent);
@@ -928,6 +940,11 @@
     }
 
     @Override
+    public @NonNull Context createFeatureContext(@Nullable String featureId) {
+        return mBase.createFeatureContext(featureId);
+    }
+
+    @Override
     public boolean isRestricted() {
         return mBase.isRestricted();
     }
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index fade0ab..d2c97c4 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -16,7 +16,6 @@
 
 package android.content;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.content.res.AssetFileDescriptor;
@@ -38,66 +37,96 @@
  * @hide
  */
 public interface IContentProvider extends IInterface {
-    public Cursor query(String callingPkg, Uri url, @Nullable String[] projection,
+    public Cursor query(String callingPkg, @Nullable String featureId, Uri url,
+            @Nullable String[] projection,
             @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal)
             throws RemoteException;
     public String getType(Uri url) throws RemoteException;
-    @UnsupportedAppUsage
-    public Uri insert(String callingPkg, Uri url, ContentValues initialValues)
-            throws RemoteException;
-    @UnsupportedAppUsage
-    public int bulkInsert(String callingPkg, Uri url, ContentValues[] initialValues)
-            throws RemoteException;
-    @UnsupportedAppUsage
-    public int delete(String callingPkg, Uri url, String selection, String[] selectionArgs)
-            throws RemoteException;
-    @UnsupportedAppUsage
-    public int update(String callingPkg, Uri url, ContentValues values, String selection,
-            String[] selectionArgs) throws RemoteException;
-    public ParcelFileDescriptor openFile(
-            String callingPkg, Uri url, String mode, ICancellationSignal signal,
-            IBinder callerToken)
-            throws RemoteException, FileNotFoundException;
-    public AssetFileDescriptor openAssetFile(
-            String callingPkg, Uri url, String mode, ICancellationSignal signal)
-            throws RemoteException, FileNotFoundException;
-
     @Deprecated
-    public default ContentProviderResult[] applyBatch(String callingPkg,
-            ArrayList<ContentProviderOperation> operations)
-                    throws RemoteException, OperationApplicationException {
-        return applyBatch(callingPkg, "unknown", operations);
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
+            + "ContentProviderClient#insert(android.net.Uri, android.content.ContentValues)} "
+            + "instead")
+    public default Uri insert(String callingPkg, Uri url, ContentValues initialValues)
+            throws RemoteException {
+        return insert(callingPkg, null, url, initialValues);
     }
+    public Uri insert(String callingPkg, String featureId, Uri url, ContentValues initialValues)
+            throws RemoteException;
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
+            + "ContentProviderClient#bulkInsert(android.net.Uri, android.content.ContentValues[])"
+            + "} instead")
+    public default int bulkInsert(String callingPkg, Uri url, ContentValues[] initialValues)
+            throws RemoteException {
+        return bulkInsert(callingPkg, null, url, initialValues);
+    }
+    public int bulkInsert(String callingPkg, String featureId, Uri url,
+            ContentValues[] initialValues) throws RemoteException;
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
+            + "ContentProviderClient#delete(android.net.Uri, java.lang.String, java.lang"
+            + ".String[])} instead")
+    public default int delete(String callingPkg, Uri url, String selection, String[] selectionArgs)
+            throws RemoteException {
+        return delete(callingPkg, null, url, selection, selectionArgs);
+    }
+    public int delete(String callingPkg, String featureId, Uri url, String selection,
+            String[] selectionArgs) throws RemoteException;
+    @Deprecated
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
+            + "ContentProviderClient#update(android.net.Uri, android.content.ContentValues, java"
+            + ".lang.String, java.lang.String[])} instead")
+    public default int update(String callingPkg, Uri url, ContentValues values, String selection,
+            String[] selectionArgs) throws RemoteException {
+        return update(callingPkg, null, url, values, selection, selectionArgs);
+    }
+    public int update(String callingPkg, String featureId, Uri url, ContentValues values,
+            String selection, String[] selectionArgs) throws RemoteException;
 
-    public ContentProviderResult[] applyBatch(String callingPkg, String authority,
-            ArrayList<ContentProviderOperation> operations)
+    public ParcelFileDescriptor openFile(String callingPkg, @Nullable String featureId, Uri url,
+            String mode, ICancellationSignal signal, IBinder callerToken)
+            throws RemoteException, FileNotFoundException;
+
+    public AssetFileDescriptor openAssetFile(String callingPkg, @Nullable String featureId,
+            Uri url, String mode, ICancellationSignal signal)
+            throws RemoteException, FileNotFoundException;
+
+    public ContentProviderResult[] applyBatch(String callingPkg, @Nullable String featureId,
+            String authority, ArrayList<ContentProviderOperation> operations)
             throws RemoteException, OperationApplicationException;
 
     @Deprecated
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
+            + "ContentProviderClient#call(java.lang.String, java.lang.String, android.os.Bundle)} "
+            + "instead")
     public default Bundle call(String callingPkg, String method,
             @Nullable String arg, @Nullable Bundle extras) throws RemoteException {
-        return call(callingPkg, "unknown", method, arg, extras);
+        return call(callingPkg, null, "unknown", method, arg, extras);
     }
 
-    public Bundle call(String callingPkg, String authority, String method,
-            @Nullable String arg, @Nullable Bundle extras) throws RemoteException;
+    public Bundle call(String callingPkg, @Nullable String featureId, String authority,
+            String method, @Nullable String arg, @Nullable Bundle extras) throws RemoteException;
 
-    public int checkUriPermission(String callingPkg, Uri uri, int uid, int modeFlags)
-            throws RemoteException;
+    public int checkUriPermission(String callingPkg, @Nullable String featureId, Uri uri, int uid,
+            int modeFlags) throws RemoteException;
 
     public ICancellationSignal createCancellationSignal() throws RemoteException;
 
-    public Uri canonicalize(String callingPkg, Uri uri) throws RemoteException;
-    public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException;
+    public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri)
+            throws RemoteException;
 
-    public boolean refresh(String callingPkg, Uri url, @Nullable Bundle args,
-            ICancellationSignal cancellationSignal) throws RemoteException;
+    public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri)
+            throws RemoteException;
+
+    public boolean refresh(String callingPkg, @Nullable String featureId, Uri url,
+            @Nullable Bundle args, ICancellationSignal cancellationSignal) throws RemoteException;
 
     // Data interchange.
     public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException;
-    public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri url, String mimeType,
-            Bundle opts, ICancellationSignal signal) throws RemoteException, FileNotFoundException;
+
+    public AssetFileDescriptor openTypedAssetFile(String callingPkg, @Nullable String featureId,
+            Uri url, String mimeType, Bundle opts, ICancellationSignal signal)
+            throws RemoteException, FileNotFoundException;
 
     /* IPC constants */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
diff --git a/core/java/android/content/PermissionChecker.java b/core/java/android/content/PermissionChecker.java
index 85f96fc..6954b31 100644
--- a/core/java/android/content/PermissionChecker.java
+++ b/core/java/android/content/PermissionChecker.java
@@ -114,6 +114,7 @@
      * @param uid The uid for which to check.
      * @param packageName The package name for which to check. If null the
      *     the first package for the calling UID will be used.
+     * @param featureId Feature in the package
      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
      *     or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
      * @param message A message describing the reason the permission was checked
@@ -123,8 +124,8 @@
     @PermissionResult
     public static int checkPermissionForDataDelivery(@NonNull Context context,
             @NonNull String permission, int pid, int uid, @Nullable String packageName,
-            @Nullable String message) {
-        return checkPermissionCommon(context, permission, pid, uid, packageName, message,
+            @Nullable String featureId, @Nullable String message) {
+        return checkPermissionCommon(context, permission, pid, uid, packageName, featureId, message,
                 true /*forDataDelivery*/);
     }
 
@@ -161,8 +162,8 @@
     @PermissionResult
     public static int checkPermissionForPreflight(@NonNull Context context,
             @NonNull String permission, int pid, int uid, @Nullable String packageName) {
-        return checkPermissionCommon(context, permission, pid, uid, packageName, null /*message*/,
-                false /*forDataDelivery*/);
+        return checkPermissionCommon(context, permission, pid, uid, packageName, null /*featureId*/,
+                null /*message*/, false /*forDataDelivery*/);
     }
 
     /**
@@ -197,7 +198,7 @@
     public static int checkSelfPermissionForDataDelivery(@NonNull Context context,
             @NonNull String permission, @Nullable String message) {
         return checkPermissionForDataDelivery(context, permission, Process.myPid(),
-                Process.myUid(), context.getPackageName(), message);
+                Process.myUid(), context.getPackageName(), context.getFeatureId(), message);
     }
 
     /**
@@ -256,6 +257,7 @@
      * @param permission The permission to check.
      * @param packageName The package name making the IPC. If null the
      *     the first package for the calling UID will be used.
+     * @param featureId The feature inside of the app
      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
      *     or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
      * @param message A message describing the reason the permission was checked
@@ -264,12 +266,13 @@
      */
     @PermissionResult
     public static int checkCallingPermissionForDataDelivery(@NonNull Context context,
-            @NonNull String permission, @Nullable String packageName, @Nullable String message) {
+            @NonNull String permission, @Nullable String packageName,
+            @Nullable String featureId, @Nullable String message) {
         if (Binder.getCallingPid() == Process.myPid()) {
             return PERMISSION_DENIED;
         }
         return checkPermissionForDataDelivery(context, permission, Binder.getCallingPid(),
-                Binder.getCallingUid(), packageName, message);
+                Binder.getCallingUid(), packageName, featureId, message);
     }
 
     /**
@@ -331,17 +334,20 @@
      * @param permission The permission to check.
      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
      *     or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
+     * @param featureId feature Id of caller (if not self)
      * @param message A message describing the reason the permission was checked
      *
      * @see #checkCallingOrSelfPermissionForPreflight(Context, String)
      */
     @PermissionResult
     public static int checkCallingOrSelfPermissionForDataDelivery(@NonNull Context context,
-            @NonNull String permission, @Nullable String message) {
+            @NonNull String permission, @Nullable String featureId, @Nullable String message) {
         String packageName = (Binder.getCallingPid() == Process.myPid())
                 ? context.getPackageName() : null;
+        featureId = (Binder.getCallingPid() == Process.myPid())
+                ? context.getFeatureId() : featureId;
         return checkPermissionForDataDelivery(context, permission, Binder.getCallingPid(),
-                Binder.getCallingUid(), packageName, message);
+                Binder.getCallingUid(), packageName, featureId, message);
     }
 
     /**
@@ -360,15 +366,15 @@
      * app's fg/gb state) and this check will not leave a trace that permission protected
      * data was delivered. When you are about to deliver the location data to a registered
      * listener you should use {@link #checkCallingOrSelfPermissionForDataDelivery(Context,
-     * String, String)} which will evaluate the permission access based on the current fg/bg state
-     * of the app and leave a record that the data was accessed.
+     * String, String, String)} which will evaluate the permission access based on the current
+     * fg/bg state of the app and leave a record that the data was accessed.
      *
      * @param context Context for accessing resources.
      * @param permission The permission to check.
      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
      *     or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
      *
-     * @see #checkCallingOrSelfPermissionForDataDelivery(Context, String, String)
+     * @see #checkCallingOrSelfPermissionForDataDelivery(Context, String, String, String)
      */
     @PermissionResult
     public static int checkCallingOrSelfPermissionForPreflight(@NonNull Context context,
@@ -380,8 +386,8 @@
     }
 
     private static int checkPermissionCommon(@NonNull Context context, @NonNull String permission,
-            int pid, int uid, @Nullable String packageName, @Nullable String message,
-            boolean forDataDelivery) {
+            int pid, int uid, @Nullable String packageName, @Nullable String featureId,
+            @Nullable String message, boolean forDataDelivery) {
         if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) {
             return PERMISSION_DENIED;
         }
@@ -401,8 +407,7 @@
         }
 
         if (forDataDelivery) {
-            // TODO moltmann: Set correct feature id
-            if (appOpsManager.noteProxyOpNoThrow(op, packageName, uid, null, message)
+            if (appOpsManager.noteProxyOpNoThrow(op, packageName, uid, featureId, message)
                     != AppOpsManager.MODE_ALLOWED) {
                 return PERMISSION_DENIED_APP_OP;
             }
diff --git a/core/java/android/content/pm/VerificationParams.java b/core/java/android/content/pm/VerificationParams.java
deleted file mode 100644
index f072167..0000000
--- a/core/java/android/content/pm/VerificationParams.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Represents verification parameters used to verify packages to be installed.
- *
- * @deprecated callers should migrate to {@link PackageInstaller}.
- * @hide
- */
-@Deprecated
-public class VerificationParams implements Parcelable {
-    /** A constant used to indicate that a uid value is not present. */
-    public static final int NO_UID = -1;
-
-    /** What we print out first when toString() is called. */
-    private static final String TO_STRING_PREFIX = "VerificationParams{";
-
-    /** The location of the supplementary verification file. */
-    private final Uri mVerificationURI;
-
-    /** URI referencing where the package was downloaded from. */
-    private final Uri mOriginatingURI;
-
-    /** HTTP referrer URI associated with the originatingURI. */
-    private final Uri mReferrer;
-
-    /** UID of the application that the install request originated from. */
-    private final int mOriginatingUid;
-
-    /** UID of application requesting the install */
-    private int mInstallerUid;
-
-    /**
-     * Creates verification specifications for installing with application verification.
-     *
-     * @param verificationURI The location of the supplementary verification
-     *            file. This can be a 'file:' or a 'content:' URI. May be {@code null}.
-     * @param originatingURI URI referencing where the package was downloaded
-     *            from. May be {@code null}.
-     * @param referrer HTTP referrer URI associated with the originatingURI.
-     *            May be {@code null}.
-     * @param originatingUid UID of the application that the install request originated
-     *            from, or NO_UID if not present
-     */
-    public VerificationParams(Uri verificationURI, Uri originatingURI, Uri referrer,
-            int originatingUid) {
-        mVerificationURI = verificationURI;
-        mOriginatingURI = originatingURI;
-        mReferrer = referrer;
-        mOriginatingUid = originatingUid;
-        mInstallerUid = NO_UID;
-    }
-
-    public Uri getVerificationURI() {
-        return mVerificationURI;
-    }
-
-    public Uri getOriginatingURI() {
-        return mOriginatingURI;
-    }
-
-    public Uri getReferrer() {
-        return mReferrer;
-    }
-
-    /** return NO_UID if not available */
-    public int getOriginatingUid() {
-        return mOriginatingUid;
-    }
-
-    /** @return NO_UID when not set */
-    public int getInstallerUid() {
-        return mInstallerUid;
-    }
-
-    public void setInstallerUid(int uid) {
-        mInstallerUid = uid;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-
-        if (!(o instanceof VerificationParams)) {
-            return false;
-        }
-
-        final VerificationParams other = (VerificationParams) o;
-
-        if (mVerificationURI == null) {
-            if (other.mVerificationURI != null) {
-                return false;
-            }
-        } else if (!mVerificationURI.equals(other.mVerificationURI)) {
-            return false;
-        }
-
-        if (mOriginatingURI == null) {
-            if (other.mOriginatingURI != null) {
-                return false;
-            }
-        } else if (!mOriginatingURI.equals(other.mOriginatingURI)) {
-            return false;
-        }
-
-        if (mReferrer == null) {
-            if (other.mReferrer != null) {
-                return false;
-            }
-        } else if (!mReferrer.equals(other.mReferrer)) {
-            return false;
-        }
-
-        if (mOriginatingUid != other.mOriginatingUid) {
-            return false;
-        }
-
-        if (mInstallerUid != other.mInstallerUid) {
-            return false;
-        }
-
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 3;
-
-        hash += 5 * (mVerificationURI == null ? 1 : mVerificationURI.hashCode());
-        hash += 7 * (mOriginatingURI == null ? 1 : mOriginatingURI.hashCode());
-        hash += 11 * (mReferrer == null ? 1 : mReferrer.hashCode());
-        hash += 13 * mOriginatingUid;
-        hash += 17 * mInstallerUid;
-
-        return hash;
-    }
-
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder(TO_STRING_PREFIX);
-
-        sb.append("mVerificationURI=");
-        sb.append(mVerificationURI.toString());
-        sb.append(",mOriginatingURI=");
-        sb.append(mOriginatingURI.toString());
-        sb.append(",mReferrer=");
-        sb.append(mReferrer.toString());
-        sb.append(",mOriginatingUid=");
-        sb.append(mOriginatingUid);
-        sb.append(",mInstallerUid=");
-        sb.append(mInstallerUid);
-        sb.append('}');
-
-        return sb.toString();
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeParcelable(mVerificationURI, 0);
-        dest.writeParcelable(mOriginatingURI, 0);
-        dest.writeParcelable(mReferrer, 0);
-        dest.writeInt(mOriginatingUid);
-        dest.writeInt(mInstallerUid);
-    }
-
-
-    private VerificationParams(Parcel source) {
-        mVerificationURI = source.readParcelable(Uri.class.getClassLoader());
-        mOriginatingURI = source.readParcelable(Uri.class.getClassLoader());
-        mReferrer = source.readParcelable(Uri.class.getClassLoader());
-        mOriginatingUid = source.readInt();
-        mInstallerUid = source.readInt();
-    }
-
-    public static final @android.annotation.NonNull Parcelable.Creator<VerificationParams> CREATOR =
-            new Parcelable.Creator<VerificationParams>() {
-        public VerificationParams createFromParcel(Parcel source) {
-                return new VerificationParams(source);
-        }
-
-        public VerificationParams[] newArray(int size) {
-            return new VerificationParams[size];
-        }
-    };
-}
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index ac1cbd4..053444b 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -66,7 +66,6 @@
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 import java.lang.annotation.Retention;
@@ -1588,6 +1587,80 @@
     }
 
     /**
+     * Copies the fields specified by mask from delta into this Configuration object. This will
+     * copy anything allowed by the mask (including undefined values).
+     * @hide
+     */
+    public void setTo(@NonNull Configuration delta, @Config int mask,
+            @WindowConfiguration.WindowConfig int windowMask) {
+        if ((mask & ActivityInfo.CONFIG_FONT_SCALE) != 0) {
+            fontScale = delta.fontScale;
+        }
+        if ((mask & ActivityInfo.CONFIG_MCC) != 0) {
+            mcc = delta.mcc;
+        }
+        if ((mask & ActivityInfo.CONFIG_MNC) != 0) {
+            mnc = delta.mnc;
+        }
+        if ((mask & ActivityInfo.CONFIG_LOCALE) != 0) {
+            mLocaleList = delta.mLocaleList;
+            if (!mLocaleList.isEmpty()) {
+                locale = (Locale) delta.locale.clone();
+            }
+        }
+        if ((mask & ActivityInfo.CONFIG_LAYOUT_DIRECTION) != 0) {
+            final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK;
+            screenLayout = (screenLayout & ~SCREENLAYOUT_LAYOUTDIR_MASK) | deltaScreenLayoutDir;
+        }
+        if ((mask & ActivityInfo.CONFIG_LOCALE) != 0) {
+            userSetLocale = delta.userSetLocale;
+        }
+        if ((mask & ActivityInfo.CONFIG_TOUCHSCREEN) != 0) {
+            touchscreen = delta.touchscreen;
+        }
+        if ((mask & ActivityInfo.CONFIG_KEYBOARD) != 0) {
+            keyboard = delta.keyboard;
+        }
+        if ((mask & ActivityInfo.CONFIG_KEYBOARD_HIDDEN) != 0) {
+            keyboardHidden = delta.keyboardHidden;
+            hardKeyboardHidden = delta.hardKeyboardHidden;
+            navigationHidden = delta.navigationHidden;
+        }
+        if ((mask & ActivityInfo.CONFIG_NAVIGATION) != 0) {
+            navigation = delta.navigation;
+        }
+        if ((mask & ActivityInfo.CONFIG_ORIENTATION) != 0) {
+            orientation = delta.orientation;
+        }
+        if ((mask & ActivityInfo.CONFIG_SCREEN_LAYOUT) != 0) {
+            // Not enough granularity for each component unfortunately.
+            screenLayout = screenLayout | (delta.screenLayout & ~SCREENLAYOUT_LAYOUTDIR_MASK);
+        }
+        if ((mask & ActivityInfo.CONFIG_COLOR_MODE) != 0) {
+            colorMode = delta.colorMode;
+        }
+        if ((mask & ActivityInfo.CONFIG_UI_MODE) != 0) {
+            uiMode = delta.uiMode;
+        }
+        if ((mask & ActivityInfo.CONFIG_SCREEN_SIZE) != 0) {
+            screenWidthDp = delta.screenWidthDp;
+            screenHeightDp = delta.screenHeightDp;
+        }
+        if ((mask & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0) {
+            smallestScreenWidthDp = delta.smallestScreenWidthDp;
+        }
+        if ((mask & ActivityInfo.CONFIG_DENSITY) != 0) {
+            densityDpi = delta.densityDpi;
+        }
+        if ((mask & ActivityInfo.CONFIG_ASSETS_PATHS) != 0) {
+            assetsSeq = delta.assetsSeq;
+        }
+        if ((mask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0) {
+            windowConfiguration.setTo(delta.windowConfiguration, windowMask);
+        }
+    }
+
+    /**
      * Return a bit mask of the differences between this Configuration
      * object and the given one.  Does not change the values of either.  Any
      * undefined fields in <var>delta</var> are ignored.
@@ -2641,75 +2714,4 @@
         // For persistence, we don't care about assetsSeq and WindowConfiguration, so do not read it
         // out.
     }
-
-
-    /**
-     * Writes the Configuration's member fields as attributes into the XmlSerializer.
-     * The serializer is expected to have already started a tag so that attributes can be
-     * immediately written.
-     *
-     * @param xml The serializer to which to write the attributes.
-     * @param config The Configuration whose member fields to write.
-     * {@hide}
-     */
-    public static void writeXmlAttrs(XmlSerializer xml, Configuration config) throws IOException {
-        XmlUtils.writeIntAttribute(xml, XML_ATTR_FONT_SCALE,
-                Float.floatToIntBits(config.fontScale));
-        if (config.mcc != 0) {
-            XmlUtils.writeIntAttribute(xml, XML_ATTR_MCC, config.mcc);
-        }
-        if (config.mnc != 0) {
-            XmlUtils.writeIntAttribute(xml, XML_ATTR_MNC, config.mnc);
-        }
-        config.fixUpLocaleList();
-        if (!config.mLocaleList.isEmpty()) {
-           XmlUtils.writeStringAttribute(xml, XML_ATTR_LOCALES, config.mLocaleList.toLanguageTags());
-        }
-        if (config.touchscreen != TOUCHSCREEN_UNDEFINED) {
-            XmlUtils.writeIntAttribute(xml, XML_ATTR_TOUCHSCREEN, config.touchscreen);
-        }
-        if (config.keyboard != KEYBOARD_UNDEFINED) {
-            XmlUtils.writeIntAttribute(xml, XML_ATTR_KEYBOARD, config.keyboard);
-        }
-        if (config.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED) {
-            XmlUtils.writeIntAttribute(xml, XML_ATTR_KEYBOARD_HIDDEN, config.keyboardHidden);
-        }
-        if (config.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED) {
-            XmlUtils.writeIntAttribute(xml, XML_ATTR_HARD_KEYBOARD_HIDDEN,
-                    config.hardKeyboardHidden);
-        }
-        if (config.navigation != NAVIGATION_UNDEFINED) {
-            XmlUtils.writeIntAttribute(xml, XML_ATTR_NAVIGATION, config.navigation);
-        }
-        if (config.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED) {
-            XmlUtils.writeIntAttribute(xml, XML_ATTR_NAVIGATION_HIDDEN, config.navigationHidden);
-        }
-        if (config.orientation != ORIENTATION_UNDEFINED) {
-            XmlUtils.writeIntAttribute(xml, XML_ATTR_ORIENTATION, config.orientation);
-        }
-        if (config.screenLayout != SCREENLAYOUT_UNDEFINED) {
-            XmlUtils.writeIntAttribute(xml, XML_ATTR_SCREEN_LAYOUT, config.screenLayout);
-        }
-        if (config.colorMode != COLOR_MODE_UNDEFINED) {
-            XmlUtils.writeIntAttribute(xml, XML_ATTR_COLOR_MODE, config.colorMode);
-        }
-        if (config.uiMode != 0) {
-            XmlUtils.writeIntAttribute(xml, XML_ATTR_UI_MODE, config.uiMode);
-        }
-        if (config.screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) {
-            XmlUtils.writeIntAttribute(xml, XML_ATTR_SCREEN_WIDTH, config.screenWidthDp);
-        }
-        if (config.screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) {
-            XmlUtils.writeIntAttribute(xml, XML_ATTR_SCREEN_HEIGHT, config.screenHeightDp);
-        }
-        if (config.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
-            XmlUtils.writeIntAttribute(xml, XML_ATTR_SMALLEST_WIDTH, config.smallestScreenWidthDp);
-        }
-        if (config.densityDpi != DENSITY_DPI_UNDEFINED) {
-            XmlUtils.writeIntAttribute(xml, XML_ATTR_DENSITY, config.densityDpi);
-        }
-
-        // For persistence, we do not care about assetsSeq and window configuration, so do not write
-        // it out.
-    }
 }
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index fbcc785..1f29d1a 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1125,6 +1125,37 @@
             new Key<android.util.Range<Integer>>("android.control.postRawSensitivityBoostRange", new TypeReference<android.util.Range<Integer>>() {{ }});
 
     /**
+     * <p>The list of bokeh modes that are supported by this camera device, and each bokeh mode's
+     * maximum streaming (non-stall) size with bokeh effect.</p>
+     * <p>For OFF mode, the camera behaves normally with no bokeh effect.</p>
+     * <p>For STILL_CAPTURE mode, the maximum streaming dimension specifies the limit under which
+     * bokeh is effective when capture intent is PREVIEW. Note that when capture intent is
+     * PREVIEW, the bokeh effect may not be as high quality compared to STILL_CAPTURE intent
+     * in order to maintain reasonable frame rate. The maximum streaming dimension must be one
+     * of the YUV_420_888 or PRIVATE resolutions in availableStreamConfigurations, or (0, 0)
+     * if preview bokeh is not supported. If the application configures a stream larger than
+     * the maximum streaming dimension, bokeh effect may not be applied for this stream for
+     * PREVIEW intent.</p>
+     * <p>For CONTINUOUS mode, the maximum streaming dimension specifies the limit under which
+     * bokeh is effective. This dimension must be one of the YUV_420_888 or PRIVATE resolutions
+     * in availableStreamConfigurations, and if the sensor maximum resolution is larger than or
+     * equal to 1080p, the maximum streaming dimension must be at least 1080p. If the
+     * application configures a stream with larger dimension, the stream may not have bokeh
+     * effect applied.</p>
+     * <p><b>Units</b>: (mode, width, height)</p>
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     *
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     */
+    @PublicKey
+    @NonNull
+    public static final Key<android.hardware.camera2.params.CapabilityAndMaxSize[]> CONTROL_AVAILABLE_BOKEH_CAPABILITIES =
+            new Key<android.hardware.camera2.params.CapabilityAndMaxSize[]>("android.control.availableBokehCapabilities", android.hardware.camera2.params.CapabilityAndMaxSize[].class);
+
+    /**
      * <p>List of edge enhancement modes for {@link CaptureRequest#EDGE_MODE android.edge.mode} that are supported by this camera
      * device.</p>
      * <p>Full-capability camera devices must always support OFF; camera devices that support
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 2fa6125..799c716 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -2444,6 +2444,34 @@
     public static final int CONTROL_VIDEO_STABILIZATION_MODE_ON = 1;
 
     //
+    // Enumeration values for CaptureRequest#CONTROL_BOKEH_MODE
+    //
+
+    /**
+     * <p>Bokeh mode is disabled.</p>
+     * @see CaptureRequest#CONTROL_BOKEH_MODE
+     */
+    public static final int CONTROL_BOKEH_MODE_OFF = 0;
+
+    /**
+     * <p>High quality bokeh mode is enabled for all non-raw streams (including YUV,
+     * JPEG, and IMPLEMENTATION_DEFINED) when capture intent is STILL_CAPTURE. Due to the
+     * extra image processing, this mode may introduce additional stall to non-raw streams.
+     * This mode should be used in high quality still capture use case.</p>
+     * @see CaptureRequest#CONTROL_BOKEH_MODE
+     */
+    public static final int CONTROL_BOKEH_MODE_STILL_CAPTURE = 1;
+
+    /**
+     * <p>Bokeh effect must not slow down capture rate relative to sensor raw output,
+     * and the effect is applied to all processed streams no larger than the maximum
+     * streaming dimension. This mode should be used if performance and power are a
+     * priority, such as video recording.</p>
+     * @see CaptureRequest#CONTROL_BOKEH_MODE
+     */
+    public static final int CONTROL_BOKEH_MODE_CONTINUOUS = 2;
+
+    //
     // Enumeration values for CaptureRequest#EDGE_MODE
     //
 
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 43c197a..5c76dff 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -994,7 +994,7 @@
      * application controls how the color mapping is performed.</p>
      * <p>We define the expected processing pipeline below. For consistency
      * across devices, this is always the case with TRANSFORM_MATRIX.</p>
-     * <p>When either FULL or HIGH_QUALITY is used, the camera device may
+     * <p>When either FAST or HIGH_QUALITY is used, the camera device may
      * do additional processing but {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
      * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform} will still be provided by the
      * camera device (in the results) and be roughly correct.</p>
@@ -2094,6 +2094,52 @@
             new Key<Boolean>("android.control.enableZsl", boolean.class);
 
     /**
+     * <p>Whether bokeh mode is enabled for a particular capture request.</p>
+     * <p>With bokeh mode, the camera device may blur out the parts of scene that are not in
+     * focus, creating a bokeh (or shallow depth of field) effect for people or objects.</p>
+     * <p>When set to STILL_CAPTURE bokeh mode with STILL_CAPTURE capture intent, due to the extra
+     * processing needed for high quality bokeh effect, the stall may be longer than when
+     * capture intent is not STILL_CAPTURE.</p>
+     * <p>When set to STILL_CAPTURE bokeh mode with PREVIEW capture intent,</p>
+     * <ul>
+     * <li>If the camera device has BURST_CAPTURE capability, the frame rate requirement of
+     * BURST_CAPTURE must still be met.</li>
+     * <li>All streams not larger than the maximum streaming dimension for STILL_CAPTURE mode
+     * (queried via {@link android.hardware.camera2.CameraCharacteristics#CONTROL_AVAILABLE_BOKEH_CAPABILITIES })
+     * will have preview bokeh effect applied.</li>
+     * </ul>
+     * <p>When set to CONTINUOUS mode, configured streams dimension should not exceed this mode's
+     * maximum streaming dimension in order to have bokeh effect applied. Bokeh effect may not
+     * be available for streams larger than the maximum streaming dimension.</p>
+     * <p>Switching between different bokeh modes may involve reconfiguration of the camera
+     * pipeline, resulting in long latency. The application should check this key against the
+     * available session keys queried via
+     * {@link android.hardware.camera2.CameraCharacteristics#getAvailableSessionKeys }.</p>
+     * <p>When bokeh mode is on, the camera device may override certain control parameters, such as
+     * reduce frame rate or use face priority scene mode, to achieve best power and quality
+     * tradeoffs. When turned on, AE, AWB, and AF run in auto modes, and only the mandatory
+     * stream combinations of LIMITED hardware level are guaranteed.</p>
+     * <p>For a logical multi-camera, bokeh may be implemented by stereo vision from sub-cameras
+     * with different field of view. As a result, when bokeh mode is enabled, the camera device
+     * may override android.scaler.CropRegion, and the field of view will be smaller than when
+     * bokeh mode is off.</p>
+     * <p><b>Possible values:</b>
+     * <ul>
+     *   <li>{@link #CONTROL_BOKEH_MODE_OFF OFF}</li>
+     *   <li>{@link #CONTROL_BOKEH_MODE_STILL_CAPTURE STILL_CAPTURE}</li>
+     *   <li>{@link #CONTROL_BOKEH_MODE_CONTINUOUS CONTINUOUS}</li>
+     * </ul></p>
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     * @see #CONTROL_BOKEH_MODE_OFF
+     * @see #CONTROL_BOKEH_MODE_STILL_CAPTURE
+     * @see #CONTROL_BOKEH_MODE_CONTINUOUS
+     */
+    @PublicKey
+    @NonNull
+    public static final Key<Integer> CONTROL_BOKEH_MODE =
+            new Key<Integer>("android.control.bokehMode", int.class);
+
+    /**
      * <p>Operation mode for edge
      * enhancement.</p>
      * <p>Edge enhancement improves sharpness and details in the captured image. OFF means
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 1007fd9..2d0ec6d 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -398,7 +398,7 @@
      * application controls how the color mapping is performed.</p>
      * <p>We define the expected processing pipeline below. For consistency
      * across devices, this is always the case with TRANSFORM_MATRIX.</p>
-     * <p>When either FULL or HIGH_QUALITY is used, the camera device may
+     * <p>When either FAST or HIGH_QUALITY is used, the camera device may
      * do additional processing but {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
      * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform} will still be provided by the
      * camera device (in the results) and be roughly correct.</p>
@@ -2324,6 +2324,52 @@
             new Key<Integer>("android.control.afSceneChange", int.class);
 
     /**
+     * <p>Whether bokeh mode is enabled for a particular capture request.</p>
+     * <p>With bokeh mode, the camera device may blur out the parts of scene that are not in
+     * focus, creating a bokeh (or shallow depth of field) effect for people or objects.</p>
+     * <p>When set to STILL_CAPTURE bokeh mode with STILL_CAPTURE capture intent, due to the extra
+     * processing needed for high quality bokeh effect, the stall may be longer than when
+     * capture intent is not STILL_CAPTURE.</p>
+     * <p>When set to STILL_CAPTURE bokeh mode with PREVIEW capture intent,</p>
+     * <ul>
+     * <li>If the camera device has BURST_CAPTURE capability, the frame rate requirement of
+     * BURST_CAPTURE must still be met.</li>
+     * <li>All streams not larger than the maximum streaming dimension for STILL_CAPTURE mode
+     * (queried via {@link android.hardware.camera2.CameraCharacteristics#CONTROL_AVAILABLE_BOKEH_CAPABILITIES })
+     * will have preview bokeh effect applied.</li>
+     * </ul>
+     * <p>When set to CONTINUOUS mode, configured streams dimension should not exceed this mode's
+     * maximum streaming dimension in order to have bokeh effect applied. Bokeh effect may not
+     * be available for streams larger than the maximum streaming dimension.</p>
+     * <p>Switching between different bokeh modes may involve reconfiguration of the camera
+     * pipeline, resulting in long latency. The application should check this key against the
+     * available session keys queried via
+     * {@link android.hardware.camera2.CameraCharacteristics#getAvailableSessionKeys }.</p>
+     * <p>When bokeh mode is on, the camera device may override certain control parameters, such as
+     * reduce frame rate or use face priority scene mode, to achieve best power and quality
+     * tradeoffs. When turned on, AE, AWB, and AF run in auto modes, and only the mandatory
+     * stream combinations of LIMITED hardware level are guaranteed.</p>
+     * <p>For a logical multi-camera, bokeh may be implemented by stereo vision from sub-cameras
+     * with different field of view. As a result, when bokeh mode is enabled, the camera device
+     * may override android.scaler.CropRegion, and the field of view will be smaller than when
+     * bokeh mode is off.</p>
+     * <p><b>Possible values:</b>
+     * <ul>
+     *   <li>{@link #CONTROL_BOKEH_MODE_OFF OFF}</li>
+     *   <li>{@link #CONTROL_BOKEH_MODE_STILL_CAPTURE STILL_CAPTURE}</li>
+     *   <li>{@link #CONTROL_BOKEH_MODE_CONTINUOUS CONTINUOUS}</li>
+     * </ul></p>
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     * @see #CONTROL_BOKEH_MODE_OFF
+     * @see #CONTROL_BOKEH_MODE_STILL_CAPTURE
+     * @see #CONTROL_BOKEH_MODE_CONTINUOUS
+     */
+    @PublicKey
+    @NonNull
+    public static final Key<Integer> CONTROL_BOKEH_MODE =
+            new Key<Integer>("android.control.bokehMode", int.class);
+
+    /**
      * <p>Operation mode for edge
      * enhancement.</p>
      * <p>Edge enhancement improves sharpness and details in the captured image. OFF means
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index e909c00..7c1ddad 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -21,6 +21,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
@@ -29,6 +30,7 @@
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.impl.MarshalQueryableArray;
 import android.hardware.camera2.marshal.impl.MarshalQueryableBlackLevelPattern;
+import android.hardware.camera2.marshal.impl.MarshalQueryableCapabilityAndMaxSize;
 import android.hardware.camera2.marshal.impl.MarshalQueryableBoolean;
 import android.hardware.camera2.marshal.impl.MarshalQueryableColorSpaceTransform;
 import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
@@ -48,6 +50,7 @@
 import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration;
 import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration;
 import android.hardware.camera2.marshal.impl.MarshalQueryableString;
+import android.hardware.camera2.params.CapabilityAndMaxSize;
 import android.hardware.camera2.params.Face;
 import android.hardware.camera2.params.HighSpeedVideoConfiguration;
 import android.hardware.camera2.params.LensShadingMap;
@@ -671,6 +674,15 @@
                         return (T) metadata.getOisSamples();
                     }
                 });
+        sGetCommandMap.put(
+                CameraCharacteristics.CONTROL_AVAILABLE_BOKEH_CAPABILITIES.getNativeKey(),
+                        new GetCommand() {
+                    @Override
+                    @SuppressWarnings("unchecked")
+                    public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+                        return (T) metadata.getBokehCapabilities();
+                    }
+                });
     }
 
     private int[] getAvailableFormats() {
@@ -1373,6 +1385,24 @@
         return samples;
     }
 
+    private CapabilityAndMaxSize[] getBokehCapabilities() {
+        CapabilityAndMaxSize[] bcs = getBase(
+                CameraCharacteristics.CONTROL_AVAILABLE_BOKEH_CAPABILITIES);
+
+        if (bcs != null) {
+            for (CapabilityAndMaxSize bc : bcs) {
+                if (bc.getMode() < CameraMetadata.CONTROL_BOKEH_MODE_OFF ||
+                        bc.getMode() > CameraMetadata.CONTROL_BOKEH_MODE_CONTINUOUS) {
+                    throw new AssertionError(String.format(
+                            "bokehMode %d is out of valid range [%d, %d]", bc.getMode(),
+                            CameraMetadata.CONTROL_BOKEH_MODE_OFF,
+                            CameraMetadata.CONTROL_BOKEH_MODE_CONTINUOUS));
+                }
+            }
+        }
+        return bcs;
+    }
+
     private <T> void setBase(CameraCharacteristics.Key<T> key, T value) {
         setBase(key.getNativeKey(), value);
     }
@@ -1750,6 +1780,7 @@
                 new MarshalQueryableBlackLevelPattern(),
                 new MarshalQueryableHighSpeedVideoConfiguration(),
                 new MarshalQueryableRecommendedStreamConfiguration(),
+                new MarshalQueryableCapabilityAndMaxSize(),
 
                 // generic parcelable marshaler (MUST BE LAST since it has lowest priority)
                 new MarshalQueryableParcelable(),
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableCapabilityAndMaxSize.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableCapabilityAndMaxSize.java
new file mode 100644
index 0000000..5c1f301
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableCapabilityAndMaxSize.java
@@ -0,0 +1,77 @@
+/*
+ * 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.hardware.camera2.marshal.impl;
+
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.params.CapabilityAndMaxSize;
+import android.hardware.camera2.utils.TypeReference;
+import android.util.Size;
+
+import java.nio.ByteBuffer;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.TYPE_INT32;
+import static android.hardware.camera2.marshal.MarshalHelpers.SIZEOF_INT32;
+
+/**
+ * Marshal {@link CapabilityAndMaxSize} to/from {@link #TYPE_INT32} {@code x CapabilityAndMaxSize.COUNT}
+ */
+public class MarshalQueryableCapabilityAndMaxSize implements MarshalQueryable<CapabilityAndMaxSize> {
+    private static final int SIZE = SIZEOF_INT32 * CapabilityAndMaxSize.COUNT;
+
+    private class MarshalerCapabilityAndMaxSize extends Marshaler<CapabilityAndMaxSize> {
+        protected MarshalerCapabilityAndMaxSize(TypeReference<CapabilityAndMaxSize> typeReference,
+                                               int nativeType) {
+            super(MarshalQueryableCapabilityAndMaxSize.this, typeReference, nativeType);
+        }
+
+        @Override
+        public void marshal(CapabilityAndMaxSize value, ByteBuffer buffer) {
+            Size maxStreamingSize = value.getMaxStreamingSize();
+
+            buffer.putInt(value.getMode());
+            buffer.putInt(maxStreamingSize.getWidth());
+            buffer.putInt(maxStreamingSize.getHeight());
+        }
+
+        @Override
+        public CapabilityAndMaxSize unmarshal(ByteBuffer buffer) {
+            int mode = buffer.getInt();
+            int maxWidth = buffer.getInt();
+            int maxHeight = buffer.getInt();
+
+            return new CapabilityAndMaxSize(mode, maxWidth, maxHeight);
+        }
+
+        @Override
+        public int getNativeSize() {
+            return SIZE;
+        }
+    }
+
+    @Override
+    public Marshaler<CapabilityAndMaxSize> createMarshaler(
+            TypeReference<CapabilityAndMaxSize> managedType, int nativeType) {
+        return new MarshalerCapabilityAndMaxSize(managedType, nativeType);
+    }
+
+    @Override
+    public boolean isTypeMappingSupported(
+            TypeReference<CapabilityAndMaxSize> managedType, int nativeType) {
+        return nativeType == TYPE_INT32 &&
+                (CapabilityAndMaxSize.class.equals(managedType.getType()));
+    }
+}
diff --git a/core/java/android/hardware/camera2/params/CapabilityAndMaxSize.java b/core/java/android/hardware/camera2/params/CapabilityAndMaxSize.java
new file mode 100644
index 0000000..be08299
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/CapabilityAndMaxSize.java
@@ -0,0 +1,126 @@
+/*
+ * 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.hardware.camera2.params;
+
+import static com.android.internal.util.Preconditions.checkArgumentInRange;
+import static com.android.internal.util.Preconditions.checkArgumentNonnegative;
+
+import android.annotation.NonNull;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.utils.HashCodeHelpers;
+import android.util.Size;
+
+/**
+ * Immutable class to store the available camera capability and its
+ * corresponding maximum streaming dimensions.
+ *
+ * @see CameraCharacteristics#CONTROL_AVAILABLE_BOKEH_CAPABILITIES
+ */
+
+public final class CapabilityAndMaxSize {
+    /**
+     * @hide
+     */
+    public static final int COUNT = 3;
+
+    private final int mMode;
+    private final int mMaxStreamingWidth;
+    private final int mMaxStreamingHeight;
+
+    /**
+     * Create a new CapabilityAndMaxSize object.
+     *
+     * @param mode supported mode for a camera capability.
+     * @param maxStreamingWidth width >= 0
+     * @param maxStreamingHeight height >= 0
+     *
+     * @hide
+     */
+    public CapabilityAndMaxSize(int mode, int maxStreamingWidth, int maxStreamingHeight) {
+        mMode = mode;
+        mMaxStreamingWidth = checkArgumentNonnegative(maxStreamingWidth,
+                "maxStreamingWidth must be nonnegative");
+        mMaxStreamingHeight = checkArgumentNonnegative(maxStreamingHeight,
+                "maxStreamingHeight must be nonnegative");
+    }
+
+    /**
+     * Return the supported mode for this capability.
+     *
+     * @return One of supported modes for the capability. For example, for available bokeh modes,
+     * this will be one of {@link CameraMetadata#CONTROL_BOKEH_MODE_OFF},
+     * {@link CameraMetadata#CONTROL_BOKEH_MODE_STILL_CAPTURE}, and
+     * {@link CameraMetadata#CONTROL_BOKEH_MODE_CONTINUOUS}.
+     */
+    public int getMode() {
+        return mMode;
+    }
+
+    /**
+     * Return the maximum streaming dimension of this capability.
+     *
+     * @return a new {@link Size} with non-negative width and height
+     */
+    public @NonNull Size getMaxStreamingSize() {
+        return new Size(mMaxStreamingWidth, mMaxStreamingHeight);
+    }
+
+    /**
+     * Compare two CapabilityAndMaxSize objects to see if they are equal.
+     *
+     * @param obj Another CapabilityAndMaxSize object
+     *
+     * @return {@code true} if the mode and max size are equal, {@code false} otherwise
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof CapabilityAndMaxSize) {
+            final CapabilityAndMaxSize other = (CapabilityAndMaxSize) obj;
+            return (mMode == other.mMode
+                    && mMaxStreamingWidth == other.mMaxStreamingWidth
+                    && mMaxStreamingHeight == other.mMaxStreamingHeight);
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return HashCodeHelpers.hashCode(mMode, mMaxStreamingWidth, mMaxStreamingHeight);
+    }
+
+    /**
+     * Return the CapabilityAndMaxSize as a string representation
+     * {@code "(mode:%d, maxStreamingSize:%d x %d)"}.
+     *
+     * @return string representation of the capability and max streaming size.
+     */
+    @Override
+    public String toString() {
+        return String.format("(mode:%d, maxStreamingSize:%d x %d)",
+                mMode, mMaxStreamingWidth, mMaxStreamingHeight);
+    }
+}
diff --git a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
index 160376b..eb5d0cb 100644
--- a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
+++ b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
@@ -58,8 +58,8 @@
      */
     private static final String VOICE_KEYPHRASE_META_DATA = "android.voice_enrollment";
     /**
-     * Activity Action: Show activity for managing the keyphrases for hotword detection.
-     * This needs to be defined by an activity that supports enrolling users for hotword/keyphrase
+     * Intent Action: for managing the keyphrases for hotword detection.
+     * This needs to be defined by a service that supports enrolling users for hotword/keyphrase
      * detection.
      */
     public static final String ACTION_MANAGE_VOICE_KEYPHRASES =
@@ -101,7 +101,7 @@
         // Find the apps that supports enrollment for hotword keyhphrases,
         // Pick a privileged app and obtain the information about the supported keyphrases
         // from its metadata.
-        List<ResolveInfo> ris = pm.queryIntentActivities(
+        List<ResolveInfo> ris = pm.queryIntentServices(
                 new Intent(ACTION_MANAGE_VOICE_KEYPHRASES), PackageManager.MATCH_DEFAULT_ONLY);
         if (ris == null || ris.isEmpty()) {
             // No application capable of enrolling for voice keyphrases is present.
@@ -116,11 +116,11 @@
         for (ResolveInfo ri : ris) {
             try {
                 ApplicationInfo ai = pm.getApplicationInfo(
-                        ri.activityInfo.packageName, PackageManager.GET_META_DATA);
+                        ri.serviceInfo.packageName, PackageManager.GET_META_DATA);
                 if ((ai.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) == 0) {
                     // The application isn't privileged (/system/priv-app).
                     // The enrollment application needs to be a privileged system app.
-                    Slog.w(TAG, ai.packageName + "is not a privileged system app");
+                    Slog.w(TAG, ai.packageName + " is not a privileged system app");
                     continue;
                 }
                 if (!Manifest.permission.MANAGE_VOICE_KEYPHRASES.equals(ai.permission)) {
@@ -137,7 +137,7 @@
                 }
             } catch (PackageManager.NameNotFoundException e) {
                 String error = "error parsing voice enrollment meta-data for "
-                        + ri.activityInfo.packageName;
+                        + ri.serviceInfo.packageName;
                 parseErrors.add(error + ": " + e);
                 Slog.w(TAG, error, e);
             }
@@ -290,7 +290,7 @@
     }
 
     /**
-     * Returns an intent to launch an activity that manages the given keyphrase
+     * Returns an intent to launch an service that manages the given keyphrase
      * for the locale.
      *
      * @param action The enrollment related action that this intent is supposed to perform.
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 3e325b7..e3259ff 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -57,6 +57,9 @@
     private static final String TAG = "NetworkCapabilities";
     private static final int INVALID_UID = -1;
 
+    // Set to true when private DNS is broken.
+    private boolean mPrivateDnsBroken;
+
     /**
      * @hide
      */
@@ -86,6 +89,7 @@
         mUids = null;
         mEstablishingVpnAppUid = INVALID_UID;
         mSSID = null;
+        mPrivateDnsBroken = false;
     }
 
     /**
@@ -104,6 +108,7 @@
         mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid;
         mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
         mSSID = nc.mSSID;
+        mPrivateDnsBroken = nc.mPrivateDnsBroken;
     }
 
     /**
@@ -557,6 +562,9 @@
         }
         if (mLinkUpBandwidthKbps != 0 || mLinkDownBandwidthKbps != 0) return "link bandwidth";
         if (hasSignalStrength()) return "signalStrength";
+        if (isPrivateDnsBroken()) {
+            return "privateDnsBroken";
+        }
         return null;
     }
 
@@ -1443,7 +1451,8 @@
                 && equalsSpecifier(that)
                 && equalsTransportInfo(that)
                 && equalsUids(that)
-                && equalsSSID(that));
+                && equalsSSID(that)
+                && equalsPrivateDnsBroken(that));
     }
 
     @Override
@@ -1460,7 +1469,8 @@
                 + (mSignalStrength * 29)
                 + Objects.hashCode(mUids) * 31
                 + Objects.hashCode(mSSID) * 37
-                + Objects.hashCode(mTransportInfo) * 41;
+                + Objects.hashCode(mTransportInfo) * 41
+                + Objects.hashCode(mPrivateDnsBroken) * 43;
     }
 
     @Override
@@ -1479,6 +1489,7 @@
         dest.writeInt(mSignalStrength);
         dest.writeArraySet(mUids);
         dest.writeString(mSSID);
+        dest.writeBoolean(mPrivateDnsBroken);
     }
 
     public static final @android.annotation.NonNull Creator<NetworkCapabilities> CREATOR =
@@ -1498,6 +1509,7 @@
                 netCap.mUids = (ArraySet<UidRange>) in.readArraySet(
                         null /* ClassLoader, null for default */);
                 netCap.mSSID = in.readString();
+                netCap.mPrivateDnsBroken = in.readBoolean();
                 return netCap;
             }
             @Override
@@ -1555,6 +1567,10 @@
             sb.append(" SSID: ").append(mSSID);
         }
 
+        if (mPrivateDnsBroken) {
+            sb.append(" Private DNS is broken");
+        }
+
         sb.append("]");
         return sb.toString();
     }
@@ -1706,4 +1722,28 @@
     public boolean isMetered() {
         return !hasCapability(NET_CAPABILITY_NOT_METERED);
     }
+
+    /**
+     * Check if private dns is broken.
+     *
+     * @return {@code true} if {@code mPrivateDnsBroken} is set when private DNS is broken.
+     * @hide
+     */
+    public boolean isPrivateDnsBroken() {
+        return mPrivateDnsBroken;
+    }
+
+    /**
+     * Set mPrivateDnsBroken to true when private dns is broken.
+     *
+     * @param broken the status of private DNS to be set.
+     * @hide
+     */
+    public void setPrivateDnsBroken(boolean broken) {
+        mPrivateDnsBroken = broken;
+    }
+
+    private boolean equalsPrivateDnsBroken(NetworkCapabilities nc) {
+        return mPrivateDnsBroken == nc.mPrivateDnsBroken;
+    }
 }
diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java
index 9ba3bd9..4ad52d5 100644
--- a/core/java/android/net/NetworkMisc.java
+++ b/core/java/android/net/NetworkMisc.java
@@ -77,6 +77,12 @@
      */
     public boolean 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.
+     */
+    public boolean hasShownBroken;
+
     public NetworkMisc() {
     }
 
diff --git a/core/java/android/net/util/SocketUtils.java b/core/java/android/net/util/SocketUtils.java
index 489a292..e9ea99f 100644
--- a/core/java/android/net/util/SocketUtils.java
+++ b/core/java/android/net/util/SocketUtils.java
@@ -77,7 +77,9 @@
 
     /**
      * Make a socket address that packet socket can send packets to.
+     * @deprecated Use {@link #makePacketSocketAddress(int, int, byte[])} instead.
      */
+    @Deprecated
     @NonNull
     public static SocketAddress makePacketSocketAddress(int ifIndex, @NonNull byte[] hwAddr) {
         return new PacketSocketAddress(
@@ -87,6 +89,18 @@
     }
 
     /**
+     * Make a socket address that packet socket can send packets to.
+     */
+    @NonNull
+    public static SocketAddress makePacketSocketAddress(int protocol, int ifIndex,
+            @NonNull byte[] hwAddr) {
+        return new PacketSocketAddress(
+                protocol /* sll_protocol */,
+                ifIndex /* sll_ifindex */,
+                hwAddr /* sll_addr */);
+    }
+
+    /**
      * @see IoBridge#closeAndSignalBlockedThreads(FileDescriptor)
      */
     public static void closeSocket(@Nullable FileDescriptor fd) throws IOException {
diff --git a/core/java/android/os/BasicShellCommandHandler.java b/core/java/android/os/BasicShellCommandHandler.java
new file mode 100644
index 0000000..5bd5d61
--- /dev/null
+++ b/core/java/android/os/BasicShellCommandHandler.java
@@ -0,0 +1,320 @@
+/*
+ * 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.os;
+
+import android.util.Log;
+
+import java.io.BufferedInputStream;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+/**
+ * Helper for implementing {@link Binder#onShellCommand Binder.onShellCommand}. This is meant to
+ * be copied into mainline modules, so this class must not use any hidden APIs.
+ *
+ * @hide
+ */
+public abstract class BasicShellCommandHandler {
+    static final String TAG = "ShellCommand";
+    static final boolean DEBUG = false;
+
+    private Binder mTarget;
+    private FileDescriptor mIn;
+    private FileDescriptor mOut;
+    private FileDescriptor mErr;
+    private String[] mArgs;
+
+    private String mCmd;
+    private int mArgPos;
+    private String mCurArgData;
+
+    private FileInputStream mFileIn;
+    private FileOutputStream mFileOut;
+    private FileOutputStream mFileErr;
+
+    private PrintWriter mOutPrintWriter;
+    private PrintWriter mErrPrintWriter;
+    private InputStream mInputStream;
+
+    public void init(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
+            String[] args, int firstArgPos) {
+        mTarget = target;
+        mIn = in;
+        mOut = out;
+        mErr = err;
+        mArgs = args;
+        mCmd = null;
+        mArgPos = firstArgPos;
+        mCurArgData = null;
+        mFileIn = null;
+        mFileOut = null;
+        mFileErr = null;
+        mOutPrintWriter = null;
+        mErrPrintWriter = null;
+        mInputStream = null;
+    }
+
+    public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
+            String[] args) {
+        String cmd;
+        int start;
+        if (args != null && args.length > 0) {
+            cmd = args[0];
+            start = 1;
+        } else {
+            cmd = null;
+            start = 0;
+        }
+        init(target, in, out, err, args, start);
+        mCmd = cmd;
+
+        if (DEBUG) {
+            RuntimeException here = new RuntimeException("here");
+            here.fillInStackTrace();
+            Log.d(TAG, "Starting command " + mCmd + " on " + mTarget, here);
+            Log.d(TAG, "Calling uid=" + Binder.getCallingUid()
+                    + " pid=" + Binder.getCallingPid());
+        }
+        int res = -1;
+        try {
+            res = onCommand(mCmd);
+            if (DEBUG) Log.d(TAG, "Executed command " + mCmd + " on " + mTarget);
+        } catch (Throwable e) {
+            // Unlike usual calls, in this case if an exception gets thrown
+            // back to us we want to print it back in to the dump data, since
+            // that is where the caller expects all interesting information to
+            // go.
+            PrintWriter eout = getErrPrintWriter();
+            eout.println();
+            eout.println("Exception occurred while executing: " + e.getMessage());
+            e.printStackTrace(eout);
+        } finally {
+            if (DEBUG) Log.d(TAG, "Flushing output streams on " + mTarget);
+            if (mOutPrintWriter != null) {
+                mOutPrintWriter.flush();
+            }
+            if (mErrPrintWriter != null) {
+                mErrPrintWriter.flush();
+            }
+            if (DEBUG) Log.d(TAG, "Sending command result on " + mTarget);
+        }
+        if (DEBUG) Log.d(TAG, "Finished command " + mCmd + " on " + mTarget);
+        return res;
+    }
+
+    /**
+     * Return the raw FileDescriptor for the output stream.
+     */
+    public FileDescriptor getOutFileDescriptor() {
+        return mOut;
+    }
+
+    /**
+     * Return direct raw access (not buffered) to the command's output data stream.
+     */
+    public OutputStream getRawOutputStream() {
+        if (mFileOut == null) {
+            mFileOut = new FileOutputStream(mOut);
+        }
+        return mFileOut;
+    }
+
+    /**
+     * Return a PrintWriter for formatting output to {@link #getRawOutputStream()}.
+     */
+    public PrintWriter getOutPrintWriter() {
+        if (mOutPrintWriter == null) {
+            mOutPrintWriter = new PrintWriter(getRawOutputStream());
+        }
+        return mOutPrintWriter;
+    }
+
+    /**
+     * Return the raw FileDescriptor for the error stream.
+     */
+    public FileDescriptor getErrFileDescriptor() {
+        return mErr;
+    }
+
+    /**
+     * Return direct raw access (not buffered) to the command's error output data stream.
+     */
+    public OutputStream getRawErrorStream() {
+        if (mFileErr == null) {
+            mFileErr = new FileOutputStream(mErr);
+        }
+        return mFileErr;
+    }
+
+    /**
+     * Return a PrintWriter for formatting output to {@link #getRawErrorStream()}.
+     */
+    public PrintWriter getErrPrintWriter() {
+        if (mErr == null) {
+            return getOutPrintWriter();
+        }
+        if (mErrPrintWriter == null) {
+            mErrPrintWriter = new PrintWriter(getRawErrorStream());
+        }
+        return mErrPrintWriter;
+    }
+
+    /**
+     * Return the raw FileDescriptor for the input stream.
+     */
+    public FileDescriptor getInFileDescriptor() {
+        return mIn;
+    }
+
+    /**
+     * Return direct raw access (not buffered) to the command's input data stream.
+     */
+    public InputStream getRawInputStream() {
+        if (mFileIn == null) {
+            mFileIn = new FileInputStream(mIn);
+        }
+        return mFileIn;
+    }
+
+    /**
+     * Return buffered access to the command's {@link #getRawInputStream()}.
+     */
+    public InputStream getBufferedInputStream() {
+        if (mInputStream == null) {
+            mInputStream = new BufferedInputStream(getRawInputStream());
+        }
+        return mInputStream;
+    }
+
+    /**
+     * Return the next option on the command line -- that is an argument that
+     * starts with '-'.  If the next argument is not an option, null is returned.
+     */
+    public String getNextOption() {
+        if (mCurArgData != null) {
+            String prev = mArgs[mArgPos - 1];
+            throw new IllegalArgumentException("No argument expected after \"" + prev + "\"");
+        }
+        if (mArgPos >= mArgs.length) {
+            return null;
+        }
+        String arg = mArgs[mArgPos];
+        if (!arg.startsWith("-")) {
+            return null;
+        }
+        mArgPos++;
+        if (arg.equals("--")) {
+            return null;
+        }
+        if (arg.length() > 1 && arg.charAt(1) != '-') {
+            if (arg.length() > 2) {
+                mCurArgData = arg.substring(2);
+                return arg.substring(0, 2);
+            } else {
+                mCurArgData = null;
+                return arg;
+            }
+        }
+        mCurArgData = null;
+        return arg;
+    }
+
+    /**
+     * Return the next argument on the command line, whatever it is; if there are
+     * no arguments left, return null.
+     */
+    public String getNextArg() {
+        if (mCurArgData != null) {
+            String arg = mCurArgData;
+            mCurArgData = null;
+            return arg;
+        } else if (mArgPos < mArgs.length) {
+            return mArgs[mArgPos++];
+        } else {
+            return null;
+        }
+    }
+
+    public String peekNextArg() {
+        if (mCurArgData != null) {
+            return mCurArgData;
+        } else if (mArgPos < mArgs.length) {
+            return mArgs[mArgPos];
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Return the next argument on the command line, whatever it is; if there are
+     * no arguments left, throws an IllegalArgumentException to report this to the user.
+     */
+    public String getNextArgRequired() {
+        String arg = getNextArg();
+        if (arg == null) {
+            String prev = mArgs[mArgPos - 1];
+            throw new IllegalArgumentException("Argument expected after \"" + prev + "\"");
+        }
+        return arg;
+    }
+
+    public int handleDefaultCommands(String cmd) {
+        if (cmd == null || "help".equals(cmd) || "-h".equals(cmd)) {
+            onHelp();
+        } else {
+            getOutPrintWriter().println("Unknown command: " + cmd);
+        }
+        return -1;
+    }
+
+    public Binder getTarget() {
+        return mTarget;
+    }
+
+    public String[] getAllArgs() {
+        return mArgs;
+    }
+
+    /**
+     * Implement parsing and execution of a command.  If it isn't a command you understand,
+     * call {@link #handleDefaultCommands(String)} and return its result as a last resort.
+     * Use {@link #getNextOption()}, {@link #getNextArg()}, and {@link #getNextArgRequired()}
+     * to process additional command line arguments.  Command output can be written to
+     * {@link #getOutPrintWriter()} and errors to {@link #getErrPrintWriter()}.
+     *
+     * <p class="caution">Note that no permission checking has been done before entering this
+     * function, so you need to be sure to do your own security verification for any commands you
+     * are executing.  The easiest way to do this is to have the ShellCommand contain
+     * only a reference to your service's aidl interface, and do all of your command
+     * implementations on top of that -- that way you can rely entirely on your executing security
+     * code behind that interface.</p>
+     *
+     * @param cmd The first command line argument representing the name of the command to execute.
+     * @return Return the command result; generally 0 or positive indicates success and
+     * negative values indicate error.
+     */
+    public abstract int onCommand(String cmd);
+
+    /**
+     * Implement this to print help text about your command to {@link #getOutPrintWriter()}.
+     */
+    public abstract void onHelp();
+}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index c5c0945..3ae1fe6 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -17,10 +17,11 @@
 package android.os;
 
 import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
-import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION;
 
+import android.annotation.IntDef;
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
+import android.app.job.JobParameters;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.server.ServerProtoEnums;
@@ -44,10 +45,11 @@
 import com.android.internal.location.gnssmetrics.GnssMetrics;
 import com.android.internal.os.BatterySipper;
 import com.android.internal.os.BatteryStatsHelper;
-import com.android.internal.util.Preconditions;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.text.DecimalFormat;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -56,7 +58,6 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.function.Function;
 
 /**
  * A class providing access to battery usage statistics, including information on
@@ -76,7 +77,7 @@
     protected static final boolean SCREEN_OFF_RPM_STATS_ENABLED = false;
 
     /** @hide */
-    public static final String SERVICE_NAME = "batterystats";
+    public static final String SERVICE_NAME = Context.BATTERY_STATS_SERVICE;
 
     /**
      * A constant indicating a partial wake lock timer.
@@ -223,6 +224,15 @@
     @Deprecated
     public static final int STATS_SINCE_UNPLUGGED = 2;
 
+    /** @hide */
+    @IntDef(flag = true, prefix = { "STATS_" }, value = {
+            STATS_SINCE_CHARGED,
+            STATS_CURRENT,
+            STATS_SINCE_UNPLUGGED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface StatName {}
+
     // NOTE: Update this list if you add/change any stats above.
     // These characters are supposed to represent "total", "last", "current",
     // and "unplugged". They were shortened for efficiency sake.
@@ -408,40 +418,6 @@
     };
 
     /**
-     * "Job stop reason codes" from the job scheduler subsystem, which we can't refer to from this
-     * class, so we initialize it from the job scheduler side at runtime using
-     * {@link #setJobStopReasons}.
-     */
-    private static int[] sJobStopReasonCodes = {0};
-
-    /**
-     * A function that converts the "job stop reason codes" to their names.
-     *
-     * Similarly to {@link #sJobStopReasonCodes} it's initialized by the job scheduler subsystem
-     * using {@link #setJobStopReasons}.
-     */
-    private static Function<Integer, String> sJobStopReasonNameConverter = (x) -> "unknown";
-
-    /**
-     * Set by the job scheduler subsystem to "push" job stop reasons, and a function that returns
-     * the "name" of each code. We do it this way to remove a build time dependency from this
-     * class to the job scheduler framework code.
-     *
-     * Note the passed array will be used as-is, without copying. The caller must not change
-     * the array it passed to it.
-     *
-     * @hide
-     */
-    public static void setJobStopReasons(int[] reasonCodes,
-            Function<Integer, String> jobStopReasonNameConverter) {
-        Preconditions.checkArgument(reasonCodes.length > 0);
-        Preconditions.checkArgument(jobStopReasonNameConverter != null);
-
-        sJobStopReasonCodes = reasonCodes;
-        sJobStopReasonNameConverter = jobStopReasonNameConverter;
-    }
-
-    /**
      * State for keeping track of counting information.
      */
     public static abstract class Counter {
@@ -911,7 +887,6 @@
          */
         public static final int[] CRITICAL_PROC_STATES = {
                 PROCESS_STATE_TOP,
-                PROCESS_STATE_FOREGROUND_SERVICE_LOCATION,
                 PROCESS_STATE_BOUND_TOP, PROCESS_STATE_FOREGROUND_SERVICE,
                 PROCESS_STATE_FOREGROUND
         };
@@ -2490,6 +2465,25 @@
 
     public static final int NUM_WIFI_SUPPL_STATES = WIFI_SUPPL_STATE_UNINITIALIZED+1;
 
+    /** @hide */
+    @IntDef(flag = true, prefix = { "WIFI_SUPPL_STATE_" }, value = {
+            WIFI_SUPPL_STATE_INVALID,
+            WIFI_SUPPL_STATE_DISCONNECTED,
+            WIFI_SUPPL_STATE_INTERFACE_DISABLED,
+            WIFI_SUPPL_STATE_INACTIVE,
+            WIFI_SUPPL_STATE_SCANNING,
+            WIFI_SUPPL_STATE_AUTHENTICATING,
+            WIFI_SUPPL_STATE_ASSOCIATING,
+            WIFI_SUPPL_STATE_ASSOCIATED,
+            WIFI_SUPPL_STATE_FOUR_WAY_HANDSHAKE,
+            WIFI_SUPPL_STATE_GROUP_HANDSHAKE,
+            WIFI_SUPPL_STATE_COMPLETED,
+            WIFI_SUPPL_STATE_DORMANT,
+            WIFI_SUPPL_STATE_UNINITIALIZED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface WifiSupplState {}
+
     static final String[] WIFI_SUPPL_STATE_NAMES = {
         "invalid", "disconn", "disabled", "inactive", "scanning",
         "authenticating", "associating", "associated", "4-way-handshake",
@@ -2641,34 +2635,48 @@
     public static final int WIFI_STATE_ON_CONNECTED_STA_P2P = 6;
     public static final int WIFI_STATE_SOFT_AP = 7;
 
+    public static final int NUM_WIFI_STATES = WIFI_STATE_SOFT_AP + 1;
+
+    /** @hide */
+    @IntDef(flag = true, prefix = { "WIFI_STATE_" }, value = {
+            WIFI_STATE_OFF,
+            WIFI_STATE_OFF_SCANNING,
+            WIFI_STATE_ON_NO_NETWORKS,
+            WIFI_STATE_ON_DISCONNECTED,
+            WIFI_STATE_ON_CONNECTED_STA,
+            WIFI_STATE_ON_CONNECTED_P2P,
+            WIFI_STATE_ON_CONNECTED_STA_P2P,
+            WIFI_STATE_SOFT_AP
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface WifiState {}
+
     static final String[] WIFI_STATE_NAMES = {
         "off", "scanning", "no_net", "disconn",
         "sta", "p2p", "sta_p2p", "soft_ap"
     };
 
-    public static final int NUM_WIFI_STATES = WIFI_STATE_SOFT_AP+1;
-
     /**
      * Returns the time in microseconds that WiFi has been running in the given state.
      *
      * {@hide}
      */
-    public abstract long getWifiStateTime(int wifiState,
-            long elapsedRealtimeUs, int which);
+    public abstract long getWifiStateTime(@WifiState int wifiState,
+            long elapsedRealtimeUs, @StatName int which);
 
     /**
      * Returns the number of times that WiFi has entered the given state.
      *
      * {@hide}
      */
-    public abstract int getWifiStateCount(int wifiState, int which);
+    public abstract int getWifiStateCount(@WifiState int wifiState, @StatName int which);
 
     /**
      * Returns the {@link Timer} object that tracks the given WiFi state.
      *
      * {@hide}
      */
-    public abstract Timer getWifiStateTimer(int wifiState);
+    public abstract Timer getWifiStateTimer(@WifiState int wifiState);
 
     /**
      * Returns the time in microseconds that the wifi supplicant has been
@@ -2676,7 +2684,8 @@
      *
      * {@hide}
      */
-    public abstract long getWifiSupplStateTime(int state, long elapsedRealtimeUs, int which);
+    public abstract long getWifiSupplStateTime(@WifiSupplState int state, long elapsedRealtimeUs,
+            @StatName int which);
 
     /**
      * Returns the number of times that the wifi supplicant has transitioned
@@ -2684,14 +2693,14 @@
      *
      * {@hide}
      */
-    public abstract int getWifiSupplStateCount(int state, int which);
+    public abstract int getWifiSupplStateCount(@WifiSupplState int state, @StatName int which);
 
     /**
      * Returns the {@link Timer} object that tracks the given wifi supplicant state.
      *
      * {@hide}
      */
-    public abstract Timer getWifiSupplStateTimer(int state);
+    public abstract Timer getWifiSupplStateTimer(@WifiSupplState int state);
 
     public static final int NUM_WIFI_SIGNAL_STRENGTH_BINS = 5;
 
@@ -4295,15 +4304,16 @@
                 }
             }
 
-            final Object[] jobCompletionArgs = new Object[sJobStopReasonCodes.length + 1];
+            final int[] jobStopReasonCodes = JobParameters.getJobStopReasonCodes();
+            final Object[] jobCompletionArgs = new Object[jobStopReasonCodes.length + 1];
 
             final ArrayMap<String, SparseIntArray> completions = u.getJobCompletionStats();
             for (int ic=completions.size()-1; ic>=0; ic--) {
                 SparseIntArray types = completions.valueAt(ic);
                 if (types != null) {
                     jobCompletionArgs[0] = "\"" + completions.keyAt(ic) + "\"";
-                    for (int i = 0; i < sJobStopReasonCodes.length; i++) {
-                        jobCompletionArgs[i + 1] = types.get(sJobStopReasonCodes[i], 0);
+                    for (int i = 0; i < jobStopReasonCodes.length; i++) {
+                        jobCompletionArgs[i + 1] = types.get(jobStopReasonCodes[i], 0);
                     }
 
                     dumpLine(pw, uid, category, JOB_COMPLETION_DATA, jobCompletionArgs);
@@ -5923,7 +5933,7 @@
                     pw.print(":");
                     for (int it=0; it<types.size(); it++) {
                         pw.print(" ");
-                        pw.print(sJobStopReasonNameConverter.apply(types.keyAt(it)));
+                        pw.print(JobParameters.getReasonCodeDescription(types.keyAt(it)));
                         pw.print("(");
                         pw.print(types.valueAt(it));
                         pw.print("x)");
@@ -7521,7 +7531,7 @@
 
                     proto.write(UidProto.JobCompletion.NAME, completions.keyAt(ic));
 
-                    for (int r : sJobStopReasonCodes) {
+                    for (int r : JobParameters.getJobStopReasonCodes()) {
                         long rToken = proto.start(UidProto.JobCompletion.REASON_COUNT);
                         proto.write(UidProto.JobCompletion.ReasonCount.NAME, r);
                         proto.write(UidProto.JobCompletion.ReasonCount.COUNT, types.get(r, 0));
diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java
new file mode 100644
index 0000000..367a868
--- /dev/null
+++ b/core/java/android/os/BatteryStatsManager.java
@@ -0,0 +1,247 @@
+/*
+ * 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.os;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.connectivity.WifiBatteryStats;
+
+import com.android.internal.app.IBatteryStats;
+
+/**
+ * This class provides an API surface for internal system components to report events that are
+ * needed for battery usage/estimation and battery blaming for apps.
+ *
+ * Note: This internally uses the same {@link IBatteryStats} binder service as the public
+ * {@link BatteryManager}.
+ * @hide
+ */
+@SystemApi
+@SystemService(Context.BATTERY_STATS_SERVICE)
+public class BatteryStatsManager {
+    private final IBatteryStats mBatteryStats;
+
+    /** @hide */
+    public BatteryStatsManager(IBatteryStats batteryStats) {
+        mBatteryStats = batteryStats;
+    }
+
+    /**
+     * Indicates that the wifi connection RSSI has changed.
+     *
+     * @param newRssi The new RSSI value.
+     */
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+    public void noteWifiRssiChanged(@IntRange(from = -127, to = 0) int newRssi) {
+        try {
+            mBatteryStats.noteWifiRssiChanged(newRssi);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Indicates that wifi was toggled on.
+     */
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+    public void noteWifiOn() {
+        try {
+            mBatteryStats.noteWifiOn();
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Indicates that wifi was toggled off.
+     */
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+    public void noteWifiOff() {
+        try {
+            mBatteryStats.noteWifiOff();
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Indicates that wifi state has changed.
+     *
+     * @param newWifiState The new wifi State.
+     * @param accessPoint SSID of the network if wifi is connected to STA, else null.
+     */
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+    public void noteWifiState(@BatteryStats.WifiState int newWifiState,
+            @Nullable String accessPoint) {
+        try {
+            mBatteryStats.noteWifiState(newWifiState, accessPoint);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Indicates that a new wifi scan has started.
+     *
+     * @param ws Worksource (to be used for battery blaming).
+     */
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+    public void noteWifiScanStartedFromSource(@NonNull WorkSource ws) {
+        try {
+            mBatteryStats.noteWifiScanStartedFromSource(ws);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Indicates that an ongoing wifi scan has stopped.
+     *
+     * @param ws Worksource (to be used for battery blaming).
+     */
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+    public void noteWifiScanStoppedFromSource(@NonNull WorkSource ws) {
+        try {
+            mBatteryStats.noteWifiScanStoppedFromSource(ws);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Indicates that a new wifi batched scan has started.
+     *
+     * @param ws Worksource (to be used for battery blaming).
+     * @param csph Channels scanned per hour.
+     */
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+    public void noteWifiBatchedScanStartedFromSource(@NonNull WorkSource ws,
+            @IntRange(from = 0) int csph) {
+        try {
+            mBatteryStats.noteWifiBatchedScanStartedFromSource(ws, csph);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Indicates that an ongoing wifi batched scan has stopped.
+     *
+     * @param ws Worksource (to be used for battery blaming).
+     */
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+    public void noteWifiBatchedScanStoppedFromSource(@NonNull WorkSource ws) {
+        try {
+            mBatteryStats.noteWifiBatchedScanStoppedFromSource(ws);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Retrieves all the wifi related battery stats.
+     *
+     * @return Instance of {@link WifiBatteryStats}.
+     */
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+    public @NonNull WifiBatteryStats getWifiBatteryStats() {
+        try {
+            return mBatteryStats.getWifiBatteryStats();
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+            return null;
+        }
+    }
+
+    /**
+     * Indicates an app acquiring full wifi lock.
+     *
+     * @param ws Worksource (to be used for battery blaming).
+     */
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+    public void noteFullWifiLockAcquiredFromSource(@NonNull WorkSource ws) {
+        try {
+            mBatteryStats.noteFullWifiLockAcquiredFromSource(ws);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Indicates an app releasing full wifi lock.
+     *
+     * @param ws Worksource (to be used for battery blaming).
+     */
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+    public void noteFullWifiLockReleasedFromSource(@NonNull WorkSource ws) {
+        try {
+            mBatteryStats.noteFullWifiLockReleasedFromSource(ws);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Indicates that supplicant state has changed.
+     *
+     * @param newSupplState The new Supplicant state.
+     * @param failedAuth Boolean indicating whether there was a connection failure due to
+     *                   authentication failure.
+     */
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+    public void noteWifiSupplicantStateChanged(@BatteryStats.WifiSupplState int newSupplState,
+            boolean failedAuth) {
+        try {
+            mBatteryStats.noteWifiSupplicantStateChanged(newSupplState, failedAuth);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Indicates that an app has acquired the wifi multicast lock.
+     *
+     * @param uid UID of the app that acquired the wifi lock (to be used for battery blaming).
+     */
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+    public void noteWifiMulticastEnabled(int uid) {
+        try {
+            mBatteryStats.noteWifiMulticastEnabled(uid);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Indicates that an app has released the wifi multicast lock.
+     *
+     * @param uid UID of the app that released the wifi lock (to be used for battery blaming).
+     */
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+    public void noteWifiMulticastDisabled(int uid) {
+        try {
+            mBatteryStats.noteWifiMulticastDisabled(uid);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index ef3afab..a856975 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -37,7 +37,9 @@
 import libcore.util.NativeAllocationRegistry;
 
 import java.io.FileDescriptor;
+import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.reflect.Modifier;
 
@@ -905,11 +907,60 @@
             @Nullable FileDescriptor err,
             @NonNull String[] args, @Nullable ShellCallback callback,
             @NonNull ResultReceiver resultReceiver) throws RemoteException {
-        FileOutputStream fout = new FileOutputStream(err != null ? err : out);
-        PrintWriter pw = new FastPrintWriter(fout);
+
+        // First, convert in, out and err to @NonNull, by redirecting any that's null to /dev/null.
+        try {
+            if (in == null) {
+                in = new FileInputStream("/dev/null").getFD();
+            }
+            if (out == null) {
+                out = new FileOutputStream("/dev/null").getFD();
+            }
+            if (err == null) {
+                err = out;
+            }
+        } catch (IOException e) {
+            PrintWriter pw = new FastPrintWriter(new FileOutputStream(err != null ? err : out));
+            pw.println("Failed to open /dev/null: " + e.getMessage());
+            pw.flush();
+            resultReceiver.send(-1, null);
+            return;
+        }
+        // Also make args @NonNull.
+        if (args == null) {
+            args = new String[0];
+        }
+
+        int result = -1;
+        try {
+            result = handleShellCommand(in, out, err, args);
+        } finally {
+            resultReceiver.send(result, null);
+        }
+    }
+
+    /**
+     * System services can implement this method to implement ADB shell commands.
+     *
+     * TODO More Javadoc.
+     * TODO Add a generic way to define subcommands and their permissions.
+     *
+     * @param in standard input.
+     * @param out standard output.
+     * @param err standard error.
+     * @param args arguments passed to the command. Can be empty. The first argument is typically
+     *             a subcommand, such as {@code run} for {@code adb shell cmd jobscheduler run}.
+     *
+     * @hide
+     */
+    // @SystemApi TODO Make it a system API.
+    protected int handleShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out,
+            @NonNull FileDescriptor err, @NonNull String[] args) {
+        FileOutputStream ferr = new FileOutputStream(err);
+        PrintWriter pw = new FastPrintWriter(ferr);
         pw.println("No shell command implementation.");
         pw.flush();
-        resultReceiver.send(0, null);
+        return 0;
     }
 
     /**
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index b3b4f78..ee95fce 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -242,32 +242,37 @@
             }
 
             Map<String, Integer> counts = new HashMap<>();
-            for (ArrayList<WeakReference<BinderProxy>> a : mMainIndexValues) {
-                if (a != null) {
-                    for (WeakReference<BinderProxy> weakRef : a) {
-                        BinderProxy bp = weakRef.get();
-                        String key;
-                        if (bp == null) {
-                            key = "<cleared weak-ref>";
-                        } else {
-                            try {
-                                key = bp.getInterfaceDescriptor();
-                                if ((key == null || key.isEmpty()) && !bp.isBinderAlive()) {
-                                    key = "<proxy to dead node>";
-                                }
-                            } catch (Throwable t) {
-                                key = "<exception during getDescriptor>";
-                            }
-                        }
-                        Integer i = counts.get(key);
-                        if (i == null) {
-                            counts.put(key, 1);
-                        } else {
-                            counts.put(key, i + 1);
-                        }
+            final ArrayList<WeakReference<BinderProxy>> proxiesToQuery =
+                    new ArrayList<WeakReference<BinderProxy>>();
+            synchronized (sProxyMap) {
+                for (ArrayList<WeakReference<BinderProxy>> a : mMainIndexValues) {
+                    if (a != null) {
+                        proxiesToQuery.addAll(a);
                     }
                 }
             }
+            for (WeakReference<BinderProxy> weakRef : proxiesToQuery) {
+                BinderProxy bp = weakRef.get();
+                String key;
+                if (bp == null) {
+                    key = "<cleared weak-ref>";
+                } else {
+                    try {
+                        key = bp.getInterfaceDescriptor();
+                        if ((key == null || key.isEmpty()) && !bp.isBinderAlive()) {
+                            key = "<proxy to dead node>";
+                        }
+                    } catch (Throwable t) {
+                        key = "<exception during getDescriptor>";
+                    }
+                }
+                Integer i = counts.get(key);
+                if (i == null) {
+                    counts.put(key, 1);
+                } else {
+                    counts.put(key, i + 1);
+                }
+            }
             Map.Entry<String, Integer>[] sorted = counts.entrySet().toArray(
                     new Map.Entry[counts.size()]);
 
@@ -355,9 +360,7 @@
      * @hide
      */
     public static InterfaceCount[] getSortedInterfaceCounts(int num) {
-        synchronized (sProxyMap) {
-            return sProxyMap.getSortedInterfaceCounts(num);
-        }
+        return sProxyMap.getSortedInterfaceCounts(num);
     }
 
     /**
@@ -377,10 +380,8 @@
      */
     public static void dumpProxyDebugInfo() {
         if (Build.IS_DEBUGGABLE) {
-            synchronized (sProxyMap) {
-                sProxyMap.dumpProxyInterfaceCounts();
-                sProxyMap.dumpPerUidProxyCounts();
-            }
+            sProxyMap.dumpProxyInterfaceCounts();
+            sProxyMap.dumpPerUidProxyCounts();
         }
     }
 
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 6d5fe53b..a92237b 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -55,6 +55,7 @@
     private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
     private static final String ENV_PRODUCT_ROOT = "PRODUCT_ROOT";
     private static final String ENV_SYSTEM_EXT_ROOT = "SYSTEM_EXT_ROOT";
+    private static final String ENV_APEX_ROOT = "APEX_ROOT";
 
     /** {@hide} */
     public static final String DIR_ANDROID = "Android";
@@ -78,7 +79,9 @@
     private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor");
     private static final File DIR_PRODUCT_ROOT = getDirectory(ENV_PRODUCT_ROOT, "/product");
     private static final File DIR_SYSTEM_EXT_ROOT = getDirectory(ENV_SYSTEM_EXT_ROOT,
-                                                           "/system_ext");
+            "/system_ext");
+    private static final File DIR_APEX_ROOT = getDirectory(ENV_APEX_ROOT,
+            "/apex");
 
     @UnsupportedAppUsage
     private static UserEnvironment sCurrentUser;
@@ -248,6 +251,16 @@
     }
 
     /**
+     * Return root directory of the apex mount point, where all the apex modules are made available
+     * to the rest of the system.
+     *
+     * @hide
+     */
+    public static @NonNull File getApexDirectory() {
+        return DIR_APEX_ROOT;
+    }
+
+    /**
      * Return the system directory for a user. This is for use by system
      * services to store files relating to the user. This directory will be
      * automatically deleted when the user is removed.
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 794d62e..dd1f8c3 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -37,7 +37,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.concurrent.Executor;
-import java.util.function.Function;
 
 /**
  * This class gives you control of the power state of the device.
@@ -828,13 +827,13 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     final Handler mHandler;
 
+    /** We lazily initialize it.*/
+    private DeviceIdleManager mDeviceIdleManager;
+
     IThermalService mThermalService;
     private final ArrayMap<OnThermalStatusChangedListener, IThermalStatusListener>
             mListenerMap = new ArrayMap<>();
 
-    private static Function<String, Boolean> sIsIgnoringBatteryOptimizationsCallback =
-            (packageName) -> false;
-
     /**
      * {@hide}
      */
@@ -844,6 +843,14 @@
         mHandler = handler;
     }
 
+    private DeviceIdleManager getDeviceIdleManager() {
+        if (mDeviceIdleManager == null) {
+            // No need for synchronization; getSystemService() will return the same object anyway.
+            mDeviceIdleManager = mContext.getSystemService(DeviceIdleManager.class);
+        }
+        return mDeviceIdleManager;
+    }
+
     /**
      * Gets the minimum supported screen brightness setting.
      * The screen may be allowed to become dimmer than this value but
@@ -1662,12 +1669,7 @@
      * {@link android.provider.Settings#ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS}.
      */
     public boolean isIgnoringBatteryOptimizations(String packageName) {
-        return sIsIgnoringBatteryOptimizationsCallback.apply(packageName);
-    }
-
-    /** @hide */
-    public static void setIsIgnoringBatteryOptimizationsCallback(Function<String, Boolean> f) {
-        sIsIgnoringBatteryOptimizationsCallback = f;
+        return getDeviceIdleManager().isApplicationWhitelisted(packageName);
     }
 
     /**
diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java
index f641731..124b6c6 100644
--- a/core/java/android/os/ServiceManagerNative.java
+++ b/core/java/android/os/ServiceManagerNative.java
@@ -86,6 +86,10 @@
         throw new RemoteException();
     }
 
+    public boolean isDeclared(String name) throws RemoteException {
+        throw new RemoteException();
+    }
+
     /**
      * Same as mServiceManager but used by apps.
      *
diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java
index 2fe8726..f3a6869 100644
--- a/core/java/android/os/ShellCommand.java
+++ b/core/java/android/os/ShellCommand.java
@@ -33,105 +33,21 @@
  * Helper for implementing {@link Binder#onShellCommand Binder.onShellCommand}.
  * @hide
  */
-public abstract class ShellCommand {
-    static final String TAG = "ShellCommand";
-    static final boolean DEBUG = false;
-
-    private Binder mTarget;
-    private FileDescriptor mIn;
-    private FileDescriptor mOut;
-    private FileDescriptor mErr;
-    private String[] mArgs;
+public abstract class ShellCommand extends BasicShellCommandHandler {
     private ShellCallback mShellCallback;
     private ResultReceiver mResultReceiver;
 
-    private String mCmd;
-    private int mArgPos;
-    private String mCurArgData;
-
-    private FileInputStream mFileIn;
-    private FileOutputStream mFileOut;
-    private FileOutputStream mFileErr;
-
-    private FastPrintWriter mOutPrintWriter;
-    private FastPrintWriter mErrPrintWriter;
-    private InputStream mInputStream;
-
-    public void init(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
-            String[] args, ShellCallback callback, int firstArgPos) {
-        mTarget = target;
-        mIn = in;
-        mOut = out;
-        mErr = err;
-        mArgs = args;
-        mShellCallback = callback;
-        mResultReceiver = null;
-        mCmd = null;
-        mArgPos = firstArgPos;
-        mCurArgData = null;
-        mFileIn = null;
-        mFileOut = null;
-        mFileErr = null;
-        mOutPrintWriter = null;
-        mErrPrintWriter = null;
-        mInputStream = null;
-    }
-
     public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
             String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
-        String cmd;
-        int start;
-        if (args != null && args.length > 0) {
-            cmd = args[0];
-            start = 1;
-        } else {
-            cmd = null;
-            start = 0;
-        }
-        init(target, in, out, err, args, callback, start);
-        mCmd = cmd;
+        mShellCallback = callback;
         mResultReceiver = resultReceiver;
+        final int result = super.exec(target, in, out, err, args);
 
-        if (DEBUG) {
-            RuntimeException here = new RuntimeException("here");
-            here.fillInStackTrace();
-            Slog.d(TAG, "Starting command " + mCmd + " on " + mTarget, here);
-            Slog.d(TAG, "Calling uid=" + Binder.getCallingUid()
-                    + " pid=" + Binder.getCallingPid() + " ShellCallback=" + getShellCallback());
+        if (mResultReceiver != null) {
+            mResultReceiver.send(result, null);
         }
-        int res = -1;
-        try {
-            res = onCommand(mCmd);
-            if (DEBUG) Slog.d(TAG, "Executed command " + mCmd + " on " + mTarget);
-        } catch (SecurityException e) {
-            PrintWriter eout = getErrPrintWriter();
-            eout.println("Security exception: " + e.getMessage());
-            eout.println();
-            e.printStackTrace(eout);
-        } catch (Throwable e) {
-            // Unlike usual calls, in this case if an exception gets thrown
-            // back to us we want to print it back in to the dump data, since
-            // that is where the caller expects all interesting information to
-            // go.
-            PrintWriter eout = getErrPrintWriter();
-            eout.println();
-            eout.println("Exception occurred while executing:");
-            e.printStackTrace(eout);
-        } finally {
-            if (DEBUG) Slog.d(TAG, "Flushing output streams on " + mTarget);
-            if (mOutPrintWriter != null) {
-                mOutPrintWriter.flush();
-            }
-            if (mErrPrintWriter != null) {
-                mErrPrintWriter.flush();
-            }
-            if (DEBUG) Slog.d(TAG, "Sending command result on " + mTarget);
-            if (mResultReceiver != null) {
-                mResultReceiver.send(res, null);
-            }
-        }
-        if (DEBUG) Slog.d(TAG, "Finished command " + mCmd + " on " + mTarget);
-        return res;
+
+        return result;
     }
 
     /**
@@ -146,90 +62,6 @@
     }
 
     /**
-     * Return the raw FileDescriptor for the output stream.
-     */
-    public FileDescriptor getOutFileDescriptor() {
-        return mOut;
-    }
-
-    /**
-     * Return direct raw access (not buffered) to the command's output data stream.
-     */
-    public OutputStream getRawOutputStream() {
-        if (mFileOut == null) {
-            mFileOut = new FileOutputStream(mOut);
-        }
-        return mFileOut;
-    }
-
-    /**
-     * Return a PrintWriter for formatting output to {@link #getRawOutputStream()}.
-     */
-    public PrintWriter getOutPrintWriter() {
-        if (mOutPrintWriter == null) {
-            mOutPrintWriter = new FastPrintWriter(getRawOutputStream());
-        }
-        return mOutPrintWriter;
-    }
-
-    /**
-     * Return the raw FileDescriptor for the error stream.
-     */
-    public FileDescriptor getErrFileDescriptor() {
-        return mErr;
-    }
-
-    /**
-     * Return direct raw access (not buffered) to the command's error output data stream.
-     */
-    public OutputStream getRawErrorStream() {
-        if (mFileErr == null) {
-            mFileErr = new FileOutputStream(mErr);
-        }
-        return mFileErr;
-    }
-
-    /**
-     * Return a PrintWriter for formatting output to {@link #getRawErrorStream()}.
-     */
-    public PrintWriter getErrPrintWriter() {
-        if (mErr == null) {
-            return getOutPrintWriter();
-        }
-        if (mErrPrintWriter == null) {
-            mErrPrintWriter = new FastPrintWriter(getRawErrorStream());
-        }
-        return mErrPrintWriter;
-    }
-
-    /**
-     * Return the raw FileDescriptor for the input stream.
-     */
-    public FileDescriptor getInFileDescriptor() {
-        return mIn;
-    }
-
-    /**
-     * Return direct raw access (not buffered) to the command's input data stream.
-     */
-    public InputStream getRawInputStream() {
-        if (mFileIn == null) {
-            mFileIn = new FileInputStream(mIn);
-        }
-        return mFileIn;
-    }
-
-    /**
-     * Return buffered access to the command's {@link #getRawInputStream()}.
-     */
-    public InputStream getBufferedInputStream() {
-        if (mInputStream == null) {
-            mInputStream = new BufferedInputStream(getRawInputStream());
-        }
-        return mInputStream;
-    }
-
-    /**
      * Helper for just system services to ask the shell to open an output file.
      * @hide
      */
@@ -256,77 +88,19 @@
         return null;
     }
 
-    /**
-     * Return the next option on the command line -- that is an argument that
-     * starts with '-'.  If the next argument is not an option, null is returned.
-     */
-    public String getNextOption() {
-        if (mCurArgData != null) {
-            String prev = mArgs[mArgPos - 1];
-            throw new IllegalArgumentException("No argument expected after \"" + prev + "\"");
+    public int handleDefaultCommands(String cmd) {
+        if ("dump".equals(cmd)) {
+            String[] newArgs = new String[getAllArgs().length-1];
+            System.arraycopy(getAllArgs(), 1, newArgs, 0, getAllArgs().length-1);
+            getTarget().doDump(getOutFileDescriptor(), getOutPrintWriter(), newArgs);
+            return 0;
         }
-        if (mArgPos >= mArgs.length) {
-            return null;
-        }
-        String arg = mArgs[mArgPos];
-        if (!arg.startsWith("-")) {
-            return null;
-        }
-        mArgPos++;
-        if (arg.equals("--")) {
-            return null;
-        }
-        if (arg.length() > 1 && arg.charAt(1) != '-') {
-            if (arg.length() > 2) {
-                mCurArgData = arg.substring(2);
-                return arg.substring(0, 2);
-            } else {
-                mCurArgData = null;
-                return arg;
-            }
-        }
-        mCurArgData = null;
-        return arg;
-    }
-
-    /**
-     * Return the next argument on the command line, whatever it is; if there are
-     * no arguments left, return null.
-     */
-    public String getNextArg() {
-        if (mCurArgData != null) {
-            String arg = mCurArgData;
-            mCurArgData = null;
-            return arg;
-        } else if (mArgPos < mArgs.length) {
-            return mArgs[mArgPos++];
-        } else {
-            return null;
-        }
+        return super.handleDefaultCommands(cmd);
     }
 
     @UnsupportedAppUsage
     public String peekNextArg() {
-        if (mCurArgData != null) {
-            return mCurArgData;
-        } else if (mArgPos < mArgs.length) {
-            return mArgs[mArgPos];
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Return the next argument on the command line, whatever it is; if there are
-     * no arguments left, throws an IllegalArgumentException to report this to the user.
-     */
-    public String getNextArgRequired() {
-        String arg = getNextArg();
-        if (arg == null) {
-            String prev = mArgs[mArgPos - 1];
-            throw new IllegalArgumentException("Argument expected after \"" + prev + "\"");
-        }
-        return arg;
+        return super.peekNextArg();
     }
 
     /**
@@ -335,43 +109,4 @@
     public ShellCallback getShellCallback() {
         return mShellCallback;
     }
-
-    public int handleDefaultCommands(String cmd) {
-        if ("dump".equals(cmd)) {
-            String[] newArgs = new String[mArgs.length-1];
-            System.arraycopy(mArgs, 1, newArgs, 0, mArgs.length-1);
-            mTarget.doDump(mOut, getOutPrintWriter(), newArgs);
-            return 0;
-        } else if (cmd == null || "help".equals(cmd) || "-h".equals(cmd)) {
-            onHelp();
-        } else {
-            getOutPrintWriter().println("Unknown command: " + cmd);
-        }
-        return -1;
-    }
-
-    /**
-     * Implement parsing and execution of a command.  If it isn't a command you understand,
-     * call {@link #handleDefaultCommands(String)} and return its result as a last resort.
-     * Use {@link #getNextOption()}, {@link #getNextArg()}, and {@link #getNextArgRequired()}
-     * to process additional command line arguments.  Command output can be written to
-     * {@link #getOutPrintWriter()} and errors to {@link #getErrPrintWriter()}.
-     *
-     * <p class="caution">Note that no permission checking has been done before entering this function,
-     * so you need to be sure to do your own security verification for any commands you
-     * are executing.  The easiest way to do this is to have the ShellCommand contain
-     * only a reference to your service's aidl interface, and do all of your command
-     * implementations on top of that -- that way you can rely entirely on your executing security
-     * code behind that interface.</p>
-     *
-     * @param cmd The first command line argument representing the name of the command to execute.
-     * @return Return the command result; generally 0 or positive indicates success and
-     * negative values indicate error.
-     */
-    public abstract int onCommand(String cmd);
-
-    /**
-     * Implement this to print help text about your command to {@link #getOutPrintWriter()}.
-     */
-    public abstract void onHelp();
 }
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index d4abf28..9d14d9d 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -151,6 +151,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public static int getInt(@NonNull String key, int def) {
         if (TRACK_KEY_ACCESS) onKeyAccess(key);
         return native_get_int(key, def);
@@ -166,6 +167,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public static long getLong(@NonNull String key, long def) {
         if (TRACK_KEY_ACCESS) onKeyAccess(key);
         return native_get_long(key, def);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index c6b63ca..3476b18 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1314,7 +1314,8 @@
     }
 
     /**
-     * Returns whether switching users is currently allowed.
+     * Returns whether switching users is currently allowed for the user this process is running
+     * under.
      * <p>
      * Switching users is not allowed in the following cases:
      * <li>the user is in a phone call</li>
@@ -1329,10 +1330,24 @@
             android.Manifest.permission.MANAGE_USERS,
             android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
     public @UserSwitchabilityResult int getUserSwitchability() {
-        final boolean allowUserSwitchingWhenSystemUserLocked = Settings.Global.getInt(
-                mContext.getContentResolver(),
-                Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED, 0) != 0;
-        final boolean systemUserUnlocked = isUserUnlocked(UserHandle.SYSTEM);
+        return getUserSwitchability(Process.myUserHandle());
+    }
+
+    /**
+     * Returns whether switching users is currently allowed for the provided user.
+     * <p>
+     * Switching users is not allowed in the following cases:
+     * <li>the user is in a phone call</li>
+     * <li>{@link #DISALLOW_USER_SWITCH} is set</li>
+     * <li>system user hasn't been unlocked yet</li>
+     *
+     * @return A {@link UserSwitchabilityResult} flag indicating if the user is switchable.
+     * @hide
+     */
+    @RequiresPermission(allOf = {Manifest.permission.READ_PHONE_STATE,
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
+    public @UserSwitchabilityResult int getUserSwitchability(UserHandle userHandle) {
         final TelephonyManager tm =
                 (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
 
@@ -1340,12 +1355,22 @@
         if (tm.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
             flags |= SWITCHABILITY_STATUS_USER_IN_CALL;
         }
-        if (hasUserRestriction(DISALLOW_USER_SWITCH)) {
+        if (hasUserRestriction(DISALLOW_USER_SWITCH, userHandle)) {
             flags |= SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED;
         }
-        if (!allowUserSwitchingWhenSystemUserLocked && !systemUserUnlocked) {
-            flags |= SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED;
+
+        // System User is always unlocked in Headless System User Mode, so ignore this flag
+        if (!isHeadlessSystemUserMode()) {
+            final boolean allowUserSwitchingWhenSystemUserLocked = Settings.Global.getInt(
+                    mContext.getContentResolver(),
+                    Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED, 0) != 0;
+            final boolean systemUserUnlocked = isUserUnlocked(UserHandle.SYSTEM);
+
+            if (!allowUserSwitchingWhenSystemUserLocked && !systemUserUnlocked) {
+                flags |= SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED;
+            }
         }
+
         return flags;
     }
 
@@ -1748,8 +1773,30 @@
         }
     }
 
-    /** {@hide} */
-    public boolean isUserUnlockingOrUnlocked(UserHandle user) {
+    /**
+     * Return whether the provided user is already running in an
+     * "unlocked" state or in the process of unlocking.
+     * <p>
+     * On devices with direct boot, a user is unlocked only after they've
+     * entered their credentials (such as a lock pattern or PIN). On devices
+     * without direct boot, a user is unlocked as soon as it starts.
+     * <p>
+     * When a user is locked, only device-protected data storage is available.
+     * When a user is unlocked, both device-protected and credential-protected
+     * private app data storage is available.
+     *
+     * <p>Requires {@code android.permission.MANAGE_USERS} or
+     * {@code android.permission.INTERACT_ACROSS_USERS}, otherwise specified {@link UserHandle user}
+     * must be the calling user or a profile associated with it.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            Manifest.permission.MANAGE_USERS,
+            Manifest.permission.INTERACT_ACROSS_USERS
+    })
+    public boolean isUserUnlockingOrUnlocked(@NonNull UserHandle user) {
         return isUserUnlockingOrUnlocked(user.getIdentifier());
     }
 
@@ -1862,7 +1909,14 @@
      * Returns the user-wide restrictions imposed on the user specified by <code>userHandle</code>.
      * @param userHandle the UserHandle of the user for whom to retrieve the restrictions.
      * @return a Bundle containing all the restrictions.
+     *
+     * <p>Requires {@code android.permission.MANAGE_USERS} or
+     * {@code android.permission.INTERACT_ACROSS_USERS}, otherwise specified {@link UserHandle user}
+     * must be the calling user or a managed profile associated with it.
      */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
     public Bundle getUserRestrictions(UserHandle userHandle) {
         try {
             return mService.getUserRestrictions(userHandle.getIdentifier());
@@ -1953,7 +2007,7 @@
      * @return {@code true} if the current user has the given restriction, {@code false} otherwise.
      */
     public boolean hasUserRestriction(String restrictionKey) {
-        return hasUserRestriction(restrictionKey, Process.myUserHandle());
+        return hasUserRestrictionForUser(restrictionKey, Process.myUserHandle());
     }
 
     /**
@@ -1965,9 +2019,29 @@
      */
     @UnsupportedAppUsage
     public boolean hasUserRestriction(String restrictionKey, UserHandle userHandle) {
+        return hasUserRestrictionForUser(restrictionKey, userHandle);
+    }
+
+    /**
+     * Returns whether the given user has been disallowed from performing certain actions
+     * or setting certain settings.
+     * @param restrictionKey the string key representing the restriction
+     * @param userHandle the UserHandle of the user for whom to retrieve the restrictions.
+     *
+     * <p>Requires {@code android.permission.MANAGE_USERS} or
+     * {@code android.permission.INTERACT_ACROSS_USERS}, otherwise specified {@link UserHandle user}
+     * must be the calling user or a managed profile associated with it.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
+    public boolean hasUserRestrictionForUser(@NonNull String restrictionKey,
+            @NonNull UserHandle userHandle) {
         try {
-            return mService.hasUserRestriction(restrictionKey,
-                    userHandle.getIdentifier());
+            return mService.hasUserRestriction(restrictionKey, userHandle.getIdentifier());
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
@@ -2568,6 +2642,22 @@
     }
 
     /**
+     * Checks if the 2 provided user handles belong to the same profile group.
+     *
+     * @param user one of the two user handles to check.
+     * @param otherUser one of the two user handles to check.
+     * @return true if the two users are in the same profile group.
+     *
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public boolean isSameProfileGroup(@NonNull UserHandle user, @NonNull UserHandle otherUser) {
+        return isSameProfileGroup(user.getIdentifier(), otherUser.getIdentifier());
+    }
+
+    /**
      * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      * @param userId one of the two user ids to check.
      * @param otherUserId one of the two user ids to check.
diff --git a/core/java/android/os/connectivity/WifiBatteryStats.java b/core/java/android/os/connectivity/WifiBatteryStats.java
index 9d2d5d8..d10a647 100644
--- a/core/java/android/os/connectivity/WifiBatteryStats.java
+++ b/core/java/android/os/connectivity/WifiBatteryStats.java
@@ -15,278 +15,385 @@
  */
 package android.os.connectivity;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.os.BatteryStats;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
- * API for Wifi power stats
+ * Class for holding Wifi related battery stats
  *
  * @hide
  */
+@SystemApi
 public final class WifiBatteryStats implements Parcelable {
+    private long mLoggingDurationMillis = 0;
+    private long mKernelActiveTimeMillis = 0;
+    private long mNumPacketsTx = 0;
+    private long mNumBytesTx = 0;
+    private long mNumPacketsRx = 0;
+    private long mNumBytesRx = 0;
+    private long mSleepTimeMillis = 0;
+    private long mScanTimeMillis = 0;
+    private long mIdleTimeMillis = 0;
+    private long mRxTimeMillis = 0;
+    private long mTxTimeMillis = 0;
+    private long mEnergyConsumedMaMillis = 0;
+    private long mNumAppScanRequest = 0;
+    private long[] mTimeInStateMillis =
+        new long[BatteryStats.NUM_WIFI_STATES];
+    private long[] mTimeInSupplicantStateMillis =
+        new long[BatteryStats.NUM_WIFI_SIGNAL_STRENGTH_BINS];
+    private long[] mTimeInRxSignalStrengthLevelMillis =
+        new long[BatteryStats.NUM_WIFI_SUPPL_STATES];
+    private long mMonitoredRailChargeConsumedMaMillis = 0;
 
-  private long mLoggingDurationMs;
-  private long mKernelActiveTimeMs;
-  private long mNumPacketsTx;
-  private long mNumBytesTx;
-  private long mNumPacketsRx;
-  private long mNumBytesRx;
-  private long mSleepTimeMs;
-  private long mScanTimeMs;
-  private long mIdleTimeMs;
-  private long mRxTimeMs;
-  private long mTxTimeMs;
-  private long mEnergyConsumedMaMs;
-  private long mNumAppScanRequest;
-  private long[] mTimeInStateMs;
-  private long[] mTimeInSupplicantStateMs;
-  private long[] mTimeInRxSignalStrengthLevelMs;
-  private long mMonitoredRailChargeConsumedMaMs;
+    public static final @NonNull Parcelable.Creator<WifiBatteryStats> CREATOR =
+            new Parcelable.Creator<WifiBatteryStats>() {
+                public WifiBatteryStats createFromParcel(Parcel in) {
+                    return new WifiBatteryStats(in);
+                }
 
-  public static final @android.annotation.NonNull Parcelable.Creator<WifiBatteryStats> CREATOR = new
-      Parcelable.Creator<WifiBatteryStats>() {
-        public WifiBatteryStats createFromParcel(Parcel in) {
-          return new WifiBatteryStats(in);
-        }
+                public WifiBatteryStats[] newArray(int size) {
+                    return new WifiBatteryStats[size];
+                }
+            };
 
-        public WifiBatteryStats[] newArray(int size) {
-          return new WifiBatteryStats[size];
-        }
-      };
+    @Override
+    public int describeContents() {
+        return 0;
+    }
 
-  public WifiBatteryStats() {
-    initialize();
-  }
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeLong(mLoggingDurationMillis);
+        out.writeLong(mKernelActiveTimeMillis);
+        out.writeLong(mNumPacketsTx);
+        out.writeLong(mNumBytesTx);
+        out.writeLong(mNumPacketsRx);
+        out.writeLong(mNumBytesRx);
+        out.writeLong(mSleepTimeMillis);
+        out.writeLong(mScanTimeMillis);
+        out.writeLong(mIdleTimeMillis);
+        out.writeLong(mRxTimeMillis);
+        out.writeLong(mTxTimeMillis);
+        out.writeLong(mEnergyConsumedMaMillis);
+        out.writeLong(mNumAppScanRequest);
+        out.writeLongArray(mTimeInStateMillis);
+        out.writeLongArray(mTimeInRxSignalStrengthLevelMillis);
+        out.writeLongArray(mTimeInSupplicantStateMillis);
+        out.writeLong(mMonitoredRailChargeConsumedMaMillis);
+    }
 
-  public void writeToParcel(Parcel out, int flags) {
-    out.writeLong(mLoggingDurationMs);
-    out.writeLong(mKernelActiveTimeMs);
-    out.writeLong(mNumPacketsTx);
-    out.writeLong(mNumBytesTx);
-    out.writeLong(mNumPacketsRx);
-    out.writeLong(mNumBytesRx);
-    out.writeLong(mSleepTimeMs);
-    out.writeLong(mScanTimeMs);
-    out.writeLong(mIdleTimeMs);
-    out.writeLong(mRxTimeMs);
-    out.writeLong(mTxTimeMs);
-    out.writeLong(mEnergyConsumedMaMs);
-    out.writeLong(mNumAppScanRequest);
-    out.writeLongArray(mTimeInStateMs);
-    out.writeLongArray(mTimeInRxSignalStrengthLevelMs);
-    out.writeLongArray(mTimeInSupplicantStateMs);
-    out.writeLong(mMonitoredRailChargeConsumedMaMs);
-  }
+    @Override
+    public boolean equals(@Nullable Object other) {
+        if (!(other instanceof WifiBatteryStats)) return false;
+        if (other == this) return true;
+        WifiBatteryStats otherStats = (WifiBatteryStats) other;
+        return this.mLoggingDurationMillis == otherStats.mLoggingDurationMillis
+                && this.mKernelActiveTimeMillis == otherStats.mKernelActiveTimeMillis
+                && this.mNumPacketsTx == otherStats.mNumPacketsTx
+                && this.mNumBytesTx == otherStats.mNumBytesTx
+                && this.mNumPacketsRx == otherStats.mNumPacketsRx
+                && this.mNumBytesRx == otherStats.mNumBytesRx
+                && this.mSleepTimeMillis == otherStats.mSleepTimeMillis
+                && this.mScanTimeMillis == otherStats.mScanTimeMillis
+                && this.mIdleTimeMillis == otherStats.mIdleTimeMillis
+                && this.mRxTimeMillis == otherStats.mRxTimeMillis
+                && this.mTxTimeMillis == otherStats.mTxTimeMillis
+                && this.mEnergyConsumedMaMillis == otherStats.mEnergyConsumedMaMillis
+                && this.mNumAppScanRequest == otherStats.mNumAppScanRequest
+                && Arrays.equals(this.mTimeInStateMillis, otherStats.mTimeInStateMillis)
+                && Arrays.equals(this.mTimeInSupplicantStateMillis,
+                    otherStats.mTimeInSupplicantStateMillis)
+                && Arrays.equals(this.mTimeInRxSignalStrengthLevelMillis,
+                    otherStats.mTimeInRxSignalStrengthLevelMillis)
+                && this.mMonitoredRailChargeConsumedMaMillis
+                    == otherStats.mMonitoredRailChargeConsumedMaMillis;
+    }
 
-  public void readFromParcel(Parcel in) {
-    mLoggingDurationMs = in.readLong();
-    mKernelActiveTimeMs = in.readLong();
-    mNumPacketsTx = in.readLong();
-    mNumBytesTx = in.readLong();
-    mNumPacketsRx = in.readLong();
-    mNumBytesRx = in.readLong();
-    mSleepTimeMs = in.readLong();
-    mScanTimeMs = in.readLong();
-    mIdleTimeMs = in.readLong();
-    mRxTimeMs = in.readLong();
-    mTxTimeMs = in.readLong();
-    mEnergyConsumedMaMs = in.readLong();
-    mNumAppScanRequest = in.readLong();
-    in.readLongArray(mTimeInStateMs);
-    in.readLongArray(mTimeInRxSignalStrengthLevelMs);
-    in.readLongArray(mTimeInSupplicantStateMs);
-    mMonitoredRailChargeConsumedMaMs = in.readLong();
-  }
+    @Override
+    public int hashCode() {
+        return Objects.hash(mLoggingDurationMillis, mKernelActiveTimeMillis, mNumPacketsTx,
+                mNumBytesTx, mNumPacketsRx, mNumBytesRx, mSleepTimeMillis, mScanTimeMillis,
+                mIdleTimeMillis, mRxTimeMillis, mTxTimeMillis, mEnergyConsumedMaMillis,
+                mNumAppScanRequest, Arrays.hashCode(mTimeInStateMillis),
+                Arrays.hashCode(mTimeInSupplicantStateMillis),
+                Arrays.hashCode(mTimeInRxSignalStrengthLevelMillis),
+                mMonitoredRailChargeConsumedMaMillis);
+    }
 
-  public long getLoggingDurationMs() {
-    return mLoggingDurationMs;
-  }
+    /** @hide **/
+    public WifiBatteryStats() {}
 
-  public long getKernelActiveTimeMs() {
-    return mKernelActiveTimeMs;
-  }
+    private void readFromParcel(Parcel in) {
+        mLoggingDurationMillis = in.readLong();
+        mKernelActiveTimeMillis = in.readLong();
+        mNumPacketsTx = in.readLong();
+        mNumBytesTx = in.readLong();
+        mNumPacketsRx = in.readLong();
+        mNumBytesRx = in.readLong();
+        mSleepTimeMillis = in.readLong();
+        mScanTimeMillis = in.readLong();
+        mIdleTimeMillis = in.readLong();
+        mRxTimeMillis = in.readLong();
+        mTxTimeMillis = in.readLong();
+        mEnergyConsumedMaMillis = in.readLong();
+        mNumAppScanRequest = in.readLong();
+        in.readLongArray(mTimeInStateMillis);
+        in.readLongArray(mTimeInRxSignalStrengthLevelMillis);
+        in.readLongArray(mTimeInSupplicantStateMillis);
+        mMonitoredRailChargeConsumedMaMillis = in.readLong();
+    }
 
-  public long getNumPacketsTx() {
-    return mNumPacketsTx;
-  }
+    /**
+     * Returns the duration for which these wifi stats were collected.
+     *
+     * @return Duration of stats collection in millis.
+     */
+    public long getLoggingDurationMillis() {
+        return mLoggingDurationMillis;
+    }
 
-  public long getNumBytesTx() {
-    return mNumBytesTx;
-  }
+    /**
+     * Returns the duration for which the kernel was active within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Duration of kernel active time in millis.
+     */
+    public long getKernelActiveTimeMillis() {
+        return mKernelActiveTimeMillis;
+    }
 
-  public long getNumPacketsRx() {
-    return mNumPacketsRx;
-  }
+    /**
+     * Returns the number of packets transmitted over wifi within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Number of packets transmitted.
+     */
+    public long getNumPacketsTx() {
+        return mNumPacketsTx;
+    }
 
-  public long getNumBytesRx() {
-    return mNumBytesRx;
-  }
+    /**
+     * Returns the number of packets received over wifi within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Number of packets received.
+     */
+    public long getNumBytesTx() {
+        return mNumBytesTx;
+    }
 
-  public long getSleepTimeMs() {
-    return mSleepTimeMs;
-  }
+    /**
+     * Returns the number of bytes transmitted over wifi within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Number of bytes transmitted.
+     */
+    public long getNumPacketsRx() {
+        return mNumPacketsRx;
+    }
 
-  public long getScanTimeMs() {
-    return mScanTimeMs;
-  }
+    /**
+     * Returns the number of bytes received over wifi within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Number of bytes received.
+     */
+    public long getNumBytesRx() {
+        return mNumBytesRx;
+    }
 
-  public long getIdleTimeMs() {
-    return mIdleTimeMs;
-  }
+    /**
+     * Returns the duration for which the device was sleeping within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Duration of sleep time in millis.
+     */
+    public long getSleepTimeMillis() {
+        return mSleepTimeMillis;
+    }
 
-  public long getRxTimeMs() {
-    return mRxTimeMs;
-  }
+    /**
+     * Returns the duration for which the device was wifi scanning within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Duration of wifi scanning time in millis.
+     */
+    public long getScanTimeMillis() {
+        return mScanTimeMillis;
+    }
 
-  public long getTxTimeMs() {
-    return mTxTimeMs;
-  }
+    /**
+     * Returns the duration for which the device was idle within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Duration of idle time in millis.
+     */
+    public long getIdleTimeMillis() {
+        return mIdleTimeMillis;
+    }
 
-  public long getEnergyConsumedMaMs() {
-    return mEnergyConsumedMaMs;
-  }
+    /**
+     * Returns the duration for which the device was receiving over wifi within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Duration of wifi reception time in millis.
+     */
+    public long getRxTimeMillis() {
+        return mRxTimeMillis;
+    }
 
-  public long getNumAppScanRequest() {
-    return mNumAppScanRequest;
-  }
+    /**
+     * Returns the duration for which the device was transmitting over wifi within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Duration of wifi transmission time in millis.
+     */
+    public long getTxTimeMillis() {
+        return mTxTimeMillis;
+    }
 
-  public long[] getTimeInStateMs() {
-    return mTimeInStateMs;
-  }
+    /**
+     * Returns an estimation of energy consumed by wifi chip within
+     * {@link #getLoggingDurationMillis()}.
+     *
+     * @return Energy consumed in millis.
+     */
+    public long getEnergyConsumedMaMillis() {
+        return mEnergyConsumedMaMillis;
+    }
 
-  public long[] getTimeInRxSignalStrengthLevelMs() {
-    return mTimeInRxSignalStrengthLevelMs;
-  }
+    /**
+     * Returns the number of app initiated wifi scans within {@link #getLoggingDurationMillis()}.
+     *
+     * @return Number of app scans.
+     */
+    public long getNumAppScanRequest() {
+        return mNumAppScanRequest;
+    }
 
-  public long[] getTimeInSupplicantStateMs() {
-    return mTimeInSupplicantStateMs;
-  }
+    /**
+     * Returns the energy consumed by wifi chip within {@link #getLoggingDurationMillis()}.
+     *
+     * @return Energy consumed in millis.
+     */
+    public long getMonitoredRailChargeConsumedMaMillis() {
+        return mMonitoredRailChargeConsumedMaMillis;
+    }
 
-  public long getMonitoredRailChargeConsumedMaMs() {
-    return mMonitoredRailChargeConsumedMaMs;
-  }
+    /** @hide */
+    public void setLoggingDurationMillis(long t) {
+        mLoggingDurationMillis = t;
+        return;
+    }
 
-  public void setLoggingDurationMs(long t) {
-    mLoggingDurationMs = t;
-    return;
-  }
+    /** @hide */
+    public void setKernelActiveTimeMillis(long t) {
+        mKernelActiveTimeMillis = t;
+        return;
+    }
 
-  public void setKernelActiveTimeMs(long t) {
-    mKernelActiveTimeMs = t;
-    return;
-  }
+    /** @hide */
+    public void setNumPacketsTx(long n) {
+        mNumPacketsTx = n;
+        return;
+    }
 
-  public void setNumPacketsTx(long n) {
-    mNumPacketsTx = n;
-    return;
-  }
+    /** @hide */
+    public void setNumBytesTx(long b) {
+        mNumBytesTx = b;
+        return;
+    }
 
-  public void setNumBytesTx(long b) {
-    mNumBytesTx = b;
-    return;
-  }
+    /** @hide */
+    public void setNumPacketsRx(long n) {
+        mNumPacketsRx = n;
+        return;
+    }
 
-  public void setNumPacketsRx(long n) {
-    mNumPacketsRx = n;
-    return;
-  }
+    /** @hide */
+    public void setNumBytesRx(long b) {
+        mNumBytesRx = b;
+        return;
+    }
 
-  public void setNumBytesRx(long b) {
-    mNumBytesRx = b;
-    return;
-  }
+    /** @hide */
+    public void setSleepTimeMillis(long t) {
+        mSleepTimeMillis = t;
+        return;
+    }
 
-  public void setSleepTimeMs(long t) {
-    mSleepTimeMs = t;
-    return;
-  }
+    /** @hide */
+    public void setScanTimeMillis(long t) {
+        mScanTimeMillis = t;
+        return;
+    }
 
-  public void setScanTimeMs(long t) {
-    mScanTimeMs = t;
-    return;
-  }
+    /** @hide */
+    public void setIdleTimeMillis(long t) {
+        mIdleTimeMillis = t;
+        return;
+    }
 
-  public void setIdleTimeMs(long t) {
-    mIdleTimeMs = t;
-    return;
-  }
+    /** @hide */
+    public void setRxTimeMillis(long t) {
+        mRxTimeMillis = t;
+        return;
+    }
 
-  public void setRxTimeMs(long t) {
-    mRxTimeMs = t;
-    return;
-  }
+    /** @hide */
+    public void setTxTimeMillis(long t) {
+        mTxTimeMillis = t;
+        return;
+    }
 
-  public void setTxTimeMs(long t) {
-    mTxTimeMs = t;
-    return;
-  }
+    /** @hide */
+    public void setEnergyConsumedMaMillis(long e) {
+        mEnergyConsumedMaMillis = e;
+        return;
+    }
 
-  public void setEnergyConsumedMaMs(long e) {
-    mEnergyConsumedMaMs = e;
-    return;
-  }
+    /** @hide */
+    public void setNumAppScanRequest(long n) {
+        mNumAppScanRequest = n;
+        return;
+    }
 
-  public void setNumAppScanRequest(long n) {
-    mNumAppScanRequest = n;
-    return;
-  }
+    /** @hide */
+    public void setTimeInStateMillis(long[] t) {
+        mTimeInStateMillis = Arrays.copyOfRange(t, 0,
+                Math.min(t.length, BatteryStats.NUM_WIFI_STATES));
+        return;
+    }
 
-  public void setTimeInStateMs(long[] t) {
-    mTimeInStateMs = Arrays.copyOfRange(t, 0,
-        Math.min(t.length, BatteryStats.NUM_WIFI_STATES));
-    return;
-  }
+    /** @hide */
+    public void setTimeInRxSignalStrengthLevelMillis(long[] t) {
+        mTimeInRxSignalStrengthLevelMillis = Arrays.copyOfRange(t, 0,
+                Math.min(t.length, BatteryStats.NUM_WIFI_SIGNAL_STRENGTH_BINS));
+        return;
+    }
 
-  public void setTimeInRxSignalStrengthLevelMs(long[] t) {
-    mTimeInRxSignalStrengthLevelMs = Arrays.copyOfRange(t, 0,
-        Math.min(t.length, BatteryStats.NUM_WIFI_SIGNAL_STRENGTH_BINS));
-    return;
-  }
+    /** @hide */
+    public void setTimeInSupplicantStateMillis(long[] t) {
+        mTimeInSupplicantStateMillis = Arrays.copyOfRange(
+                t, 0, Math.min(t.length, BatteryStats.NUM_WIFI_SUPPL_STATES));
+        return;
+    }
 
-  public void setTimeInSupplicantStateMs(long[] t) {
-    mTimeInSupplicantStateMs = Arrays.copyOfRange(
-        t, 0, Math.min(t.length, BatteryStats.NUM_WIFI_SUPPL_STATES));
-    return;
-  }
+    /** @hide */
+    public void setMonitoredRailChargeConsumedMaMillis(long monitoredRailEnergyConsumedMaMillis) {
+        mMonitoredRailChargeConsumedMaMillis = monitoredRailEnergyConsumedMaMillis;
+        return;
+    }
 
-  public void setMonitoredRailChargeConsumedMaMs(long monitoredRailEnergyConsumedMaMs) {
-    mMonitoredRailChargeConsumedMaMs = monitoredRailEnergyConsumedMaMs;
-    return;
-  }
-
-  public int describeContents() {
-    return 0;
-  }
-
-  private WifiBatteryStats(Parcel in) {
-    initialize();
-    readFromParcel(in);
-  }
-
-  private void initialize() {
-    mLoggingDurationMs = 0;
-    mKernelActiveTimeMs = 0;
-    mNumPacketsTx = 0;
-    mNumBytesTx = 0;
-    mNumPacketsRx = 0;
-    mNumBytesRx = 0;
-    mSleepTimeMs = 0;
-    mScanTimeMs = 0;
-    mIdleTimeMs = 0;
-    mRxTimeMs = 0;
-    mTxTimeMs = 0;
-    mEnergyConsumedMaMs = 0;
-    mNumAppScanRequest = 0;
-    mTimeInStateMs = new long[BatteryStats.NUM_WIFI_STATES];
-    Arrays.fill(mTimeInStateMs, 0);
-    mTimeInRxSignalStrengthLevelMs = new long[BatteryStats.NUM_WIFI_SIGNAL_STRENGTH_BINS];
-    Arrays.fill(mTimeInRxSignalStrengthLevelMs, 0);
-    mTimeInSupplicantStateMs = new long[BatteryStats.NUM_WIFI_SUPPL_STATES];
-    Arrays.fill(mTimeInSupplicantStateMs, 0);
-    mMonitoredRailChargeConsumedMaMs = 0;
-    return;
-  }
-}
\ No newline at end of file
+    private WifiBatteryStats(Parcel in) {
+        readFromParcel(in);
+    }
+}
diff --git a/core/java/android/os/image/DynamicSystemManager.java b/core/java/android/os/image/DynamicSystemManager.java
index 77fd946..0e00d5e 100644
--- a/core/java/android/os/image/DynamicSystemManager.java
+++ b/core/java/android/os/image/DynamicSystemManager.java
@@ -104,16 +104,17 @@
      * Start DynamicSystem installation. This call may take an unbounded amount of time. The caller
      * may use another thread to call the getStartProgress() to get the progress.
      *
-     * @param systemSize system size in bytes
-     * @param userdataSize userdata size in bytes
+     * @param name The DSU partition name
+     * @param size Size of the DSU image in bytes
+     * @param readOnly True if the partition is read only, e.g. system.
      * @return {@code true} if the call succeeds. {@code false} either the device does not contain
      *     enough space or a DynamicSystem is currently in use where the {@link #isInUse} would be
      *     true.
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
-    public Session startInstallation(long systemSize, long userdataSize) {
+    public Session startInstallation(String name, long size, boolean readOnly) {
         try {
-            if (mService.startInstallation(systemSize, userdataSize)) {
+            if (mService.startInstallation(name, size, readOnly)) {
                 return new Session();
             } else {
                 return null;
diff --git a/core/java/android/os/image/IDynamicSystemService.aidl b/core/java/android/os/image/IDynamicSystemService.aidl
index a6de170..75f6785 100644
--- a/core/java/android/os/image/IDynamicSystemService.aidl
+++ b/core/java/android/os/image/IDynamicSystemService.aidl
@@ -24,11 +24,12 @@
      * Start DynamicSystem installation. This call may take 60~90 seconds. The caller
      * may use another thread to call the getStartProgress() to get the progress.
      *
-     * @param systemSize system size in bytes
-     * @param userdataSize userdata size in bytes
+     * @param name The DSU partition name
+     * @param size Size of the DSU image in bytes
+     * @param readOnly True if this partition is readOnly
      * @return true if the call succeeds
      */
-    boolean startInstallation(long systemSize, long userdataSize);
+    boolean startInstallation(@utf8InCpp String name, long size, boolean readOnly);
 
     /**
      * Query the progress of the current installation operation. This can be called while
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index e456c8a..0401d7f 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -130,8 +130,10 @@
     /**
      * Namespace for how dex runs. The feature requires a reboot to reach a clean state.
      *
+     * @deprecated No longer used
      * @hide
      */
+    @Deprecated
     @SystemApi
     public static final String NAMESPACE_DEX_BOOT = "dex_boot";
 
@@ -338,6 +340,15 @@
     public static final String NAMESPACE_PRIVACY = "privacy";
 
     /**
+     * Permission related properties definitions.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final String NAMESPACE_PERMISSIONS = "permissions";
+
+    /**
      * Interface for accessing keys belonging to {@link #NAMESPACE_WINDOW_MANAGER}.
      * @hide
      */
@@ -577,9 +588,8 @@
     @RequiresPermission(WRITE_DEVICE_CONFIG)
     public static boolean setProperty(@NonNull String namespace, @NonNull String name,
             @Nullable String value, boolean makeDefault) {
-        String compositeName = createCompositeName(namespace, name);
         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
-        return Settings.Config.putString(contentResolver, compositeName, value, makeDefault);
+        return Settings.Config.putString(contentResolver, namespace, name, value, makeDefault);
     }
 
     /**
@@ -663,12 +673,6 @@
         }
     }
 
-    private static String createCompositeName(@NonNull String namespace, @NonNull String name) {
-        Preconditions.checkNotNull(namespace);
-        Preconditions.checkNotNull(name);
-        return namespace + "/" + name;
-    }
-
     private static Uri createNamespaceUri(@NonNull String namespace) {
         Preconditions.checkNotNull(namespace);
         return CONTENT_URI.buildUpon().appendPath(namespace).build();
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 2143a0d..a80153d 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -1081,7 +1081,8 @@
             // signed with platform signature can hold MANAGE_DOCUMENTS, we are going to check for
             // MANAGE_DOCUMENTS or associated URI permission here instead
             final Uri rootUri = extras.getParcelable(DocumentsContract.EXTRA_URI);
-            enforceWritePermissionInner(rootUri, getCallingPackage(), null);
+            enforceWritePermissionInner(rootUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
 
             final String rootId = DocumentsContract.getRootId(rootUri);
             ejectRoot(rootId);
@@ -1102,7 +1103,8 @@
         enforceTree(documentUri);
 
         if (METHOD_IS_CHILD_DOCUMENT.equals(method)) {
-            enforceReadPermissionInner(documentUri, getCallingPackage(), null);
+            enforceReadPermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
 
             final Uri childUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI);
             final String childAuthority = childUri.getAuthority();
@@ -1114,7 +1116,8 @@
                             && isChildDocument(documentId, childId));
 
         } else if (METHOD_CREATE_DOCUMENT.equals(method)) {
-            enforceWritePermissionInner(documentUri, getCallingPackage(), null);
+            enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
 
             final String mimeType = extras.getString(Document.COLUMN_MIME_TYPE);
             final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
@@ -1128,7 +1131,8 @@
             out.putParcelable(DocumentsContract.EXTRA_URI, newDocumentUri);
 
         } else if (METHOD_CREATE_WEB_LINK_INTENT.equals(method)) {
-            enforceWritePermissionInner(documentUri, getCallingPackage(), null);
+            enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
 
             final Bundle options = extras.getBundle(DocumentsContract.EXTRA_OPTIONS);
             final IntentSender intentSender = createWebLinkIntent(documentId, options);
@@ -1136,7 +1140,8 @@
             out.putParcelable(DocumentsContract.EXTRA_RESULT, intentSender);
 
         } else if (METHOD_RENAME_DOCUMENT.equals(method)) {
-            enforceWritePermissionInner(documentUri, getCallingPackage(), null);
+            enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
 
             final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
             final String newDocumentId = renameDocument(documentId, displayName);
@@ -1160,7 +1165,8 @@
             }
 
         } else if (METHOD_DELETE_DOCUMENT.equals(method)) {
-            enforceWritePermissionInner(documentUri, getCallingPackage(), null);
+            enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
             deleteDocument(documentId);
 
             // Document no longer exists, clean up any grants.
@@ -1170,8 +1176,10 @@
             final Uri targetUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI);
             final String targetId = DocumentsContract.getDocumentId(targetUri);
 
-            enforceReadPermissionInner(documentUri, getCallingPackage(), null);
-            enforceWritePermissionInner(targetUri, getCallingPackage(), null);
+            enforceReadPermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
+            enforceWritePermissionInner(targetUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
 
             final String newDocumentId = copyDocument(documentId, targetId);
 
@@ -1194,9 +1202,12 @@
             final Uri targetUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI);
             final String targetId = DocumentsContract.getDocumentId(targetUri);
 
-            enforceWritePermissionInner(documentUri, getCallingPackage(), null);
-            enforceReadPermissionInner(parentSourceUri, getCallingPackage(), null);
-            enforceWritePermissionInner(targetUri, getCallingPackage(), null);
+            enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
+            enforceReadPermissionInner(parentSourceUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
+            enforceWritePermissionInner(targetUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
 
             final String newDocumentId = moveDocument(documentId, parentSourceId, targetId);
 
@@ -1217,8 +1228,10 @@
             final Uri parentSourceUri = extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI);
             final String parentSourceId = DocumentsContract.getDocumentId(parentSourceUri);
 
-            enforceReadPermissionInner(parentSourceUri, getCallingPackage(), null);
-            enforceWritePermissionInner(documentUri, getCallingPackage(), null);
+            enforceReadPermissionInner(parentSourceUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
+            enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
+                    null);
             removeDocument(documentId, parentSourceId);
 
             // It's responsibility of the provider to revoke any grants, as the document may be
@@ -1227,7 +1240,8 @@
             final boolean isTreeUri = isTreeUri(documentUri);
 
             if (isTreeUri) {
-                enforceReadPermissionInner(documentUri, getCallingPackage(), null);
+                enforceReadPermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
+                        null);
             } else {
                 getContext().enforceCallingPermission(Manifest.permission.MANAGE_DOCUMENTS, null);
             }
diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java
index 8f772d4..fcbda5f 100644
--- a/core/java/android/provider/FontsContract.java
+++ b/core/java/android/provider/FontsContract.java
@@ -334,10 +334,17 @@
             return cachedTypeface;
         }
 
-        // Unfortunately the typeface is not available at this time, but requesting from the font
-        // provider takes too much time. For now, request the font data to ensure it is in the cache
-        // next time and return.
         synchronized (sLock) {
+            // It is possible that Font is loaded during the thread sleep time
+            // re-check the cache to avoid re-loading the font
+            cachedTypeface = sTypefaceCache.get(id);
+            if (cachedTypeface != null) {
+                return cachedTypeface;
+            }
+
+            // Unfortunately the typeface is not available at this time, but requesting from
+            // the font provider takes too much time. For now, request the font data to ensure
+            // it is in the cache next time and return.
             if (sHandler == null) {
                 sThread = new HandlerThread("fonts", Process.THREAD_PRIORITY_BACKGROUND);
                 sThread.start();
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index a1333df..aa67d97 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -47,6 +47,7 @@
 import android.media.ExifInterface;
 import android.media.MediaFile;
 import android.media.MediaFormat;
+import android.media.MediaMetadataRetriever;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.CancellationSignal;
@@ -589,9 +590,7 @@
      * @see MediaStore#setIncludeTrashed(Uri)
      * @see MediaStore#trash(Context, Uri)
      * @see MediaStore#untrash(Context, Uri)
-     * @removed
      */
-    @Deprecated
     public static @NonNull Uri setIncludeTrashed(@NonNull Uri uri) {
         return uri.buildUpon().appendQueryParameter(PARAM_INCLUDE_TRASHED, "1").build();
     }
@@ -830,9 +829,7 @@
      * @see MediaStore#setIncludeTrashed(Uri)
      * @see MediaStore#trash(Context, Uri)
      * @see MediaStore#untrash(Context, Uri)
-     * @removed
      */
-    @Deprecated
     public static void trash(@NonNull Context context, @NonNull Uri uri) {
         trash(context, uri, 48 * DateUtils.HOUR_IN_MILLIS);
     }
@@ -850,9 +847,7 @@
      * @see MediaStore#setIncludeTrashed(Uri)
      * @see MediaStore#trash(Context, Uri)
      * @see MediaStore#untrash(Context, Uri)
-     * @removed
      */
-    @Deprecated
     public static void trash(@NonNull Context context, @NonNull Uri uri,
             @DurationMillisLong long timeoutMillis) {
         if (timeoutMillis < 0) {
@@ -874,9 +869,7 @@
      * @see MediaStore#setIncludeTrashed(Uri)
      * @see MediaStore#trash(Context, Uri)
      * @see MediaStore#untrash(Context, Uri)
-     * @removed
      */
-    @Deprecated
     public static void untrash(@NonNull Context context, @NonNull Uri uri) {
         final ContentValues values = new ContentValues();
         values.put(MediaColumns.IS_TRASHED, 0);
@@ -907,26 +900,8 @@
         public static final String DATA = "_data";
 
         /**
-         * Hash of the media item on disk.
-         * <p>
-         * Contains a 20-byte binary blob which is the SHA-1 hash of the file as
-         * persisted on disk. For performance reasons, the hash may not be
-         * immediately available, in which case a {@code NULL} value will be
-         * returned. If the underlying file is modified, this value will be
-         * cleared and recalculated.
-         * <p>
-         * If you require the hash of a specific item, you can call
-         * {@link ContentResolver#canonicalize(Uri)}, which will block until the
-         * hash is calculated.
-         *
-         * @removed
-         */
-        @Deprecated
-        @Column(value = Cursor.FIELD_TYPE_BLOB, readOnly = true)
-        public static final String HASH = "_hash";
-
-        /**
-         * The size of the media item.
+         * Indexed value of {@link File#length()} extracted from this media
+         * item.
          */
         @BytesLong
         @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
@@ -943,12 +918,6 @@
         public static final String DISPLAY_NAME = "_display_name";
 
         /**
-         * The title of the media item.
-         */
-        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-        public static final String TITLE = "title";
-
-        /**
          * The time the media item was first added.
          */
         @CurrentTimeSecondsLong
@@ -956,14 +925,22 @@
         public static final String DATE_ADDED = "date_added";
 
         /**
-         * The time the media item was last modified.
+         * Indexed value of {@link File#lastModified()} extracted from this
+         * media item.
          */
         @CurrentTimeSecondsLong
         @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
         public static final String DATE_MODIFIED = "date_modified";
 
         /**
-         * The time the media item was taken.
+         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_DATE} or
+         * {@link ExifInterface#TAG_DATETIME_ORIGINAL} extracted from this media
+         * item.
+         * <p>
+         * Note that images must define both
+         * {@link ExifInterface#TAG_DATETIME_ORIGINAL} and
+         * {@code ExifInterface#TAG_OFFSET_TIME_ORIGINAL} to reliably determine
+         * this value in relation to the epoch.
          */
         @CurrentTimeMillisLong
         @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
@@ -989,17 +966,6 @@
         public static final String MIME_TYPE = "mime_type";
 
         /**
-         * The MTP object handle of a newly transfered file.
-         * Used to pass the new file's object handle through the media scanner
-         * from MTP to the media provider
-         * For internal use only by MTP, media scanner and media provider.
-         * @hide
-         */
-        @Deprecated
-        // @Column(Cursor.FIELD_TYPE_INTEGER)
-        public static final String MEDIA_SCANNER_NEW_OBJECT_ID = "media_scanner_new_object_id";
-
-        /**
          * Non-zero if the media file is drm-protected
          * @hide
          */
@@ -1012,6 +978,10 @@
          * Flag indicating if a media item is pending, and still being inserted
          * by its owner. While this flag is set, only the owner of the item can
          * open the underlying file; requests from other apps will be rejected.
+         * <p>
+         * Pending items are retained either until they are published by setting
+         * the field to {@code 0}, or until they expire as defined by
+         * {@link #DATE_EXPIRES}.
          *
          * @see MediaStore#setIncludePending(Uri)
          */
@@ -1020,38 +990,54 @@
 
         /**
          * Flag indicating if a media item is trashed.
+         * <p>
+         * Trashed items are retained until they expire as defined by
+         * {@link #DATE_EXPIRES}.
          *
          * @see MediaColumns#IS_TRASHED
          * @see MediaStore#setIncludeTrashed(Uri)
          * @see MediaStore#trash(Context, Uri)
          * @see MediaStore#untrash(Context, Uri)
-         * @removed
          */
-        @Deprecated
         @Column(Cursor.FIELD_TYPE_INTEGER)
         public static final String IS_TRASHED = "is_trashed";
 
         /**
          * The time the media item should be considered expired. Typically only
-         * meaningful in the context of {@link #IS_PENDING}.
+         * meaningful in the context of {@link #IS_PENDING} or
+         * {@link #IS_TRASHED}.
          */
         @CurrentTimeSecondsLong
         @Column(Cursor.FIELD_TYPE_INTEGER)
         public static final String DATE_EXPIRES = "date_expires";
 
         /**
-         * The width of the media item, in pixels.
+         * Indexed value of
+         * {@link MediaMetadataRetriever#METADATA_KEY_VIDEO_WIDTH},
+         * {@link MediaMetadataRetriever#METADATA_KEY_IMAGE_WIDTH} or
+         * {@link ExifInterface#TAG_IMAGE_WIDTH} extracted from this media item.
          */
         @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
         public static final String WIDTH = "width";
 
         /**
-         * The height of the media item, in pixels.
+         * Indexed value of
+         * {@link MediaMetadataRetriever#METADATA_KEY_VIDEO_HEIGHT},
+         * {@link MediaMetadataRetriever#METADATA_KEY_IMAGE_HEIGHT} or
+         * {@link ExifInterface#TAG_IMAGE_LENGTH} extracted from this media
+         * item.
          */
         @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
         public static final String HEIGHT = "height";
 
         /**
+         * Calculated value that combines {@link #WIDTH} and {@link #HEIGHT}
+         * into a user-presentable string.
+         */
+        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+        public static final String RESOLUTION = "resolution";
+
+        /**
          * Package name that contributed this media. The value may be
          * {@code NULL} if ownership cannot be reliably determined.
          */
@@ -1097,28 +1083,6 @@
         public static final String RELATIVE_PATH = "relative_path";
 
         /**
-         * The primary directory name this media exists under. The value may be
-         * {@code NULL} if the media doesn't have a primary directory name.
-         *
-         * @removed
-         * @deprecated Replaced by {@link #RELATIVE_PATH}.
-         */
-        @Column(Cursor.FIELD_TYPE_STRING)
-        @Deprecated
-        public static final String PRIMARY_DIRECTORY = "primary_directory";
-
-        /**
-         * The secondary directory name this media exists under. The value may
-         * be {@code NULL} if the media doesn't have a secondary directory name.
-         *
-         * @removed
-         * @deprecated Replaced by {@link #RELATIVE_PATH}.
-         */
-        @Column(Cursor.FIELD_TYPE_STRING)
-        @Deprecated
-        public static final String SECONDARY_DIRECTORY = "secondary_directory";
-
-        /**
          * The primary bucket ID of this media item. This can be useful to
          * present the user a first-level clustering of related media items.
          * This is a read-only column that is automatically computed.
@@ -1191,18 +1155,171 @@
         public static final String ORIGINAL_DOCUMENT_ID = "original_document_id";
 
         /**
-         * The duration of the media item.
+         * Indexed value of
+         * {@link MediaMetadataRetriever#METADATA_KEY_VIDEO_ROTATION},
+         * {@link MediaMetadataRetriever#METADATA_KEY_IMAGE_ROTATION}, or
+         * {@link ExifInterface#TAG_ORIENTATION} extracted from this media item.
+         * <p>
+         * For consistency the indexed value is expressed in degrees, such as 0,
+         * 90, 180, or 270.
+         */
+        @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
+        public static final String ORIENTATION = "orientation";
+
+        /**
+         * Flag indicating if the media item has been marked as being a
+         * "favorite" by the user.
+         */
+        @Column(Cursor.FIELD_TYPE_INTEGER)
+        public static final String IS_FAVORITE = "is_favorite";
+
+        // =======================================
+        // ==== MediaMetadataRetriever values ====
+        // =======================================
+
+        /**
+         * Indexed value of
+         * {@link MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER} extracted
+         * from this media item.
+         */
+        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+        public static final String CD_TRACK_NUMBER = "cd_track_number";
+
+        /**
+         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_ALBUM}
+         * extracted from this media item.
+         */
+        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+        public static final String ALBUM = "album";
+
+        /**
+         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_ARTIST}
+         * or {@link ExifInterface#TAG_ARTIST} extracted from this media item.
+         */
+        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+        public static final String ARTIST = "artist";
+
+        /**
+         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_AUTHOR}
+         * extracted from this media item.
+         */
+        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+        public static final String AUTHOR = "author";
+
+        /**
+         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_COMPOSER}
+         * extracted from this media item.
+         */
+        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+        public static final String COMPOSER = "composer";
+
+        // METADATA_KEY_DATE is DATE_TAKEN
+
+        /**
+         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_GENRE}
+         * extracted from this media item.
+         */
+        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+        public static final String GENRE = "genre";
+
+        /**
+         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_TITLE}
+         * extracted from this media item.
+         */
+        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+        public static final String TITLE = "title";
+
+        /**
+         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_YEAR}
+         * extracted from this media item.
+         */
+        @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
+        public static final String YEAR = "year";
+
+        /**
+         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_DURATION}
+         * extracted from this media item.
          */
         @DurationMillisLong
         @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
         public static final String DURATION = "duration";
 
         /**
-         * The orientation for the media item, expressed in degrees. For
-         * example, 0, 90, 180, or 270 degrees.
+         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_NUM_TRACKS}
+         * extracted from this media item.
          */
         @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
-        public static final String ORIENTATION = "orientation";
+        public static final String NUM_TRACKS = "num_tracks";
+
+        /**
+         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_WRITER}
+         * extracted from this media item.
+         */
+        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+        public static final String WRITER = "writer";
+
+        // METADATA_KEY_MIMETYPE is MIME_TYPE
+
+        /**
+         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST}
+         * extracted from this media item.
+         */
+        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+        public static final String ALBUM_ARTIST = "album_artist";
+
+        /**
+         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER}
+         * extracted from this media item.
+         */
+        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+        public static final String DISC_NUMBER = "disc_number";
+
+        /**
+         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_COMPILATION}
+         * extracted from this media item.
+         */
+        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+        public static final String COMPILATION = "compilation";
+
+        // HAS_AUDIO is ignored
+        // HAS_VIDEO is ignored
+        // VIDEO_WIDTH is WIDTH
+        // VIDEO_HEIGHT is HEIGHT
+
+        /**
+         * Indexed value of {@link MediaMetadataRetriever#METADATA_KEY_BITRATE}
+         * extracted from this media item.
+         */
+        @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
+        public static final String BITRATE = "bitrate";
+
+        // TIMED_TEXT_LANGUAGES is ignored
+        // IS_DRM is ignored
+        // LOCATION is LATITUDE and LONGITUDE
+        // VIDEO_ROTATION is ORIENTATION
+
+        /**
+         * Indexed value of
+         * {@link MediaMetadataRetriever#METADATA_KEY_CAPTURE_FRAMERATE}
+         * extracted from this media item.
+         */
+        @Column(value = Cursor.FIELD_TYPE_FLOAT, readOnly = true)
+        public static final String CAPTURE_FRAMERATE = "capture_framerate";
+
+        // HAS_IMAGE is ignored
+        // IMAGE_COUNT is ignored
+        // IMAGE_PRIMARY is ignored
+        // IMAGE_WIDTH is WIDTH
+        // IMAGE_HEIGHT is HEIGHT
+        // IMAGE_ROTATION is ORIENTATION
+        // VIDEO_FRAME_COUNT is ignored
+        // EXIF_OFFSET is ignored
+        // EXIF_LENGTH is ignored
+        // COLOR_STANDARD is ignored
+        // COLOR_TRANSFER is ignored
+        // COLOR_RANGE is ignored
+        // SAMPLERATE is ignored
+        // BITS_PER_SAMPLE is ignored
     }
 
     /**
@@ -1331,10 +1448,7 @@
             @Column(Cursor.FIELD_TYPE_STRING)
             public static final String MIME_TYPE = "mime_type";
 
-            /**
-             * The title of the media item.
-             */
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+            /** @removed promoted to parent interface */
             public static final String TITLE = "title";
 
             /**
@@ -1589,12 +1703,6 @@
          */
         public interface ImageColumns extends MediaColumns {
             /**
-             * The description of the image
-             */
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
-            public static final String DESCRIPTION = "description";
-
-            /**
              * The picasa id of the image
              *
              * @deprecated this value was only relevant for images hosted on
@@ -1656,6 +1764,34 @@
             public static final String BUCKET_DISPLAY_NAME = "bucket_display_name";
             /** @removed promoted to parent interface */
             public static final String GROUP_ID = "group_id";
+
+            /**
+             * Indexed value of {@link ExifInterface#TAG_IMAGE_DESCRIPTION}
+             * extracted from this media item.
+             */
+            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+            public static final String DESCRIPTION = "description";
+
+            /**
+             * Indexed value of {@link ExifInterface#TAG_EXPOSURE_TIME}
+             * extracted from this media item.
+             */
+            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+            public static final String EXPOSURE_TIME = "exposure_time";
+
+            /**
+             * Indexed value of {@link ExifInterface#TAG_F_NUMBER}
+             * extracted from this media item.
+             */
+            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+            public static final String F_NUMBER = "f_number";
+
+            /**
+             * Indexed value of {@link ExifInterface#TAG_ISO_SPEED_RATINGS}
+             * extracted from this media item.
+             */
+            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
+            public static final String ISO = "iso";
         }
 
         public static final class Media implements ImageColumns {
@@ -1904,6 +2040,10 @@
              * generated. Callers are responsible for their own in-memory
              * caching of returned values.
              *
+             * As of {@link android.os.Build.VERSION_CODES#Q}, this output
+             * of the thumbnail has correct rotation, don't need to rotate
+             * it again.
+             *
              * @param imageId the image item to obtain a thumbnail for.
              * @param kind optimal thumbnail size desired.
              * @return decoded thumbnail, or {@code null} if problem was
@@ -1946,6 +2086,10 @@
              * generated. Callers are responsible for their own in-memory
              * caching of returned values.
              *
+             * As of {@link android.os.Build.VERSION_CODES#Q}, this output
+             * of the thumbnail has correct rotation, don't need to rotate
+             * it again.
+             *
              * @param imageId the image item to obtain a thumbnail for.
              * @param kind optimal thumbnail size desired.
              * @return decoded thumbnail, or {@code null} if problem was
@@ -2000,6 +2144,9 @@
              * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
              * access.
              *
+             * As of {@link android.os.Build.VERSION_CODES#Q}, this thumbnail
+             * has correct rotation, don't need to rotate it again.
+             *
              * @deprecated Apps may not have filesystem permissions to directly
              *             access this path. Instead of trying to open this path
              *             directly, apps should use
@@ -2093,10 +2240,7 @@
             @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
             public static final String ARTIST_ID = "artist_id";
 
-            /**
-             * The artist who created the audio file, if any
-             */
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+            /** @removed promoted to parent interface */
             public static final String ARTIST = "artist";
 
             /**
@@ -2107,14 +2251,6 @@
             public static final String ALBUM_ARTIST = "album_artist";
 
             /**
-             * Whether the song is part of a compilation
-             * @hide
-             */
-            @Deprecated
-            // @Column(Cursor.FIELD_TYPE_STRING)
-            public static final String COMPILATION = "compilation";
-
-            /**
              * A non human readable key calculated from the ARTIST, used for
              * searching, sorting and grouping
              *
@@ -2131,10 +2267,7 @@
             @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
             public static final String ARTIST_KEY = "artist_key";
 
-            /**
-             * The composer of the audio file, if any
-             */
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+            /** @removed promoted to parent interface */
             public static final String COMPOSER = "composer";
 
             /**
@@ -2143,10 +2276,7 @@
             @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
             public static final String ALBUM_ID = "album_id";
 
-            /**
-             * The album the audio file is from, if any
-             */
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+            /** @removed promoted to parent interface */
             public static final String ALBUM = "album";
 
             /**
@@ -2973,23 +3103,11 @@
         public interface VideoColumns extends MediaColumns {
             /** @removed promoted to parent interface */
             public static final String DURATION = "duration";
-
-            /**
-             * The artist who created the video file, if any
-             */
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+            /** @removed promoted to parent interface */
             public static final String ARTIST = "artist";
-
-            /**
-             * The album the video file is from, if any
-             */
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+            /** @removed promoted to parent interface */
             public static final String ALBUM = "album";
-
-            /**
-             * The resolution of the video file, formatted as "XxY"
-             */
-            @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+            /** @removed promoted to parent interface */
             public static final String RESOLUTION = "resolution";
 
             /**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cff99f3..381d492 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -78,6 +78,7 @@
 import android.view.Display;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
 import com.android.internal.widget.ILockSettings;
 
 import java.io.IOException;
@@ -1722,6 +1723,20 @@
             = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
 
     /**
+     * Activity Action: Show Work Policy info.
+     * DPC apps can implement an activity that handles this intent in order to show device policies
+     * associated with the work profile or managed device.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     *
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_SHOW_WORK_POLICY_INFO =
+            "android.settings.SHOW_WORK_POLICY_INFO";
+
+    /**
      * Activity Action: Show screen that let user select its Autofill Service.
      * <p>
      * Input: Intent's data URI set with an application name, using the
@@ -2292,8 +2307,8 @@
                     arg.putBoolean(CALL_METHOD_MAKE_DEFAULT_KEY, true);
                 }
                 IContentProvider cp = mProviderHolder.getProvider(cr);
-                cp.call(cr.getPackageName(), mProviderHolder.mUri.getAuthority(),
-                        mCallSetCommand, name, arg);
+                cp.call(cr.getPackageName(), cr.getFeatureId(),
+                        mProviderHolder.mUri.getAuthority(), mCallSetCommand, name, arg);
             } catch (RemoteException e) {
                 Log.w(TAG, "Can't set key " + name + " in " + mUri, e);
                 return false;
@@ -2366,14 +2381,15 @@
                     if (Settings.isInSystemServer() && Binder.getCallingUid() != Process.myUid()) {
                         final long token = Binder.clearCallingIdentity();
                         try {
-                            b = cp.call(cr.getPackageName(), mProviderHolder.mUri.getAuthority(),
-                                    mCallGetCommand, name, args);
+                            b = cp.call(cr.getPackageName(), cr.getFeatureId(),
+                                    mProviderHolder.mUri.getAuthority(), mCallGetCommand, name,
+                                    args);
                         } finally {
                             Binder.restoreCallingIdentity(token);
                         }
                     } else {
-                        b = cp.call(cr.getPackageName(), mProviderHolder.mUri.getAuthority(),
-                                mCallGetCommand, name, args);
+                        b = cp.call(cr.getPackageName(), cr.getFeatureId(),
+                                mProviderHolder.mUri.getAuthority(), mCallGetCommand, name, args);
                     }
                     if (b != null) {
                         String value = b.getString(Settings.NameValueTable.VALUE);
@@ -2441,14 +2457,14 @@
                 if (Settings.isInSystemServer() && Binder.getCallingUid() != Process.myUid()) {
                     final long token = Binder.clearCallingIdentity();
                     try {
-                        c = cp.query(cr.getPackageName(), mUri, SELECT_VALUE_PROJECTION, queryArgs,
-                                null);
+                        c = cp.query(cr.getPackageName(), cr.getFeatureId(), mUri,
+                                SELECT_VALUE_PROJECTION, queryArgs, null);
                     } finally {
                         Binder.restoreCallingIdentity(token);
                     }
                 } else {
-                    c = cp.query(cr.getPackageName(), mUri, SELECT_VALUE_PROJECTION, queryArgs,
-                            null);
+                    c = cp.query(cr.getPackageName(), cr.getFeatureId(), mUri,
+                            SELECT_VALUE_PROJECTION, queryArgs, null);
                 }
                 if (c == null) {
                     Log.w(TAG, "Can't get key " + name + " from " + mUri);
@@ -2492,7 +2508,7 @@
                         boolean prefixCached = false;
                         int size = mValues.size();
                         for (int i = 0; i < size; ++i) {
-                            if (mValues.keyAt(i).startsWith(prefix + "/")) {
+                            if (mValues.keyAt(i).startsWith(prefix)) {
                                 prefixCached = true;
                                 break;
                             }
@@ -2507,7 +2523,7 @@
                             } else {
                                 for (int i = 0; i < size; ++i) {
                                     String key = mValues.keyAt(i);
-                                    if (key.startsWith(prefix + "/")) {
+                                    if (key.startsWith(prefix)) {
                                         keyValues.put(key, mValues.get(key));
                                     }
                                 }
@@ -2543,8 +2559,8 @@
                 }
 
                 // Fetch all flags for the namespace at once for caching purposes
-                Bundle b = cp.call(cr.getPackageName(), mProviderHolder.mUri.getAuthority(),
-                        mCallListCommand, null, args);
+                Bundle b = cp.call(cr.getPackageName(), cr.getFeatureId(),
+                        mProviderHolder.mUri.getAuthority(), mCallListCommand, null, args);
                 if (b == null) {
                     // Invalid response, return an empty map
                     return keyValues;
@@ -5118,8 +5134,8 @@
                 }
                 arg.putInt(CALL_METHOD_RESET_MODE_KEY, mode);
                 IContentProvider cp = sProviderHolder.getProvider(resolver);
-                cp.call(resolver.getPackageName(), sProviderHolder.mUri.getAuthority(),
-                        CALL_METHOD_RESET_SECURE, null, arg);
+                cp.call(resolver.getPackageName(), resolver.getFeatureId(),
+                        sProviderHolder.mUri.getAuthority(), CALL_METHOD_RESET_SECURE, null, arg);
             } catch (RemoteException e) {
                 Log.w(TAG, "Can't reset do defaults for " + CONTENT_URI, e);
             }
@@ -8254,6 +8270,12 @@
         public static final String AWARE_LOCK_ENABLED = "aware_lock_enabled";
 
         /**
+         * Controls whether tap gesture is enabled.
+         * @hide
+         */
+        public static final String TAP_GESTURE = "tap_gesture";
+
+        /**
          * Keys we no longer back up under the current schema, but want to continue to
          * process when restoring historical backup datasets.
          *
@@ -8809,6 +8831,13 @@
         public static final String DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS =
                 "force_desktop_mode_on_external_displays";
 
+        /**
+         * Whether to allow non-resizable apps to be freeform.
+         * @hide
+         */
+        public static final String DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM =
+                "enable_sizecompat_freeform";
+
        /**
         * Whether user has enabled development settings.
         */
@@ -10625,6 +10654,7 @@
          * @hide
          * @see com.android.server.AppOpsService.Constants
          */
+        @TestApi
         public static final String APP_OPS_CONSTANTS = "app_ops_constants";
 
         /**
@@ -12800,8 +12830,8 @@
                 }
                 arg.putInt(CALL_METHOD_RESET_MODE_KEY, mode);
                 IContentProvider cp = sProviderHolder.getProvider(resolver);
-                cp.call(resolver.getPackageName(), sProviderHolder.mUri.getAuthority(),
-                        CALL_METHOD_RESET_GLOBAL, null, arg);
+                cp.call(resolver.getPackageName(), resolver.getFeatureId(),
+                        sProviderHolder.mUri.getAuthority(), CALL_METHOD_RESET_GLOBAL, null, arg);
             } catch (RemoteException e) {
                 Log.w(TAG, "Can't reset do defaults for " + CONTENT_URI, e);
             }
@@ -13657,10 +13687,10 @@
         }
 
         /**
-         * Look up a list of names in the database, based on a common prefix.
+         * Look up a list of names in the database, within the specified namespace.
          *
          * @param resolver to access the database with
-         * @param prefix to apply to all of the names which will be fetched
+         * @param namespace to which the names belong
          * @param names to look up in the table
          * @return a non null, but possibly empty, map from name to value for any of the names that
          *         were found during lookup.
@@ -13669,16 +13699,17 @@
          */
         @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
         static Map<String, String> getStrings(@NonNull ContentResolver resolver,
-                @NonNull String prefix, @NonNull List<String> names) {
-            List<String> concatenatedNames = new ArrayList<>(names.size());
+                @NonNull String namespace, @NonNull List<String> names) {
+            List<String> compositeNames = new ArrayList<>(names.size());
             for (String name : names) {
-                concatenatedNames.add(prefix + "/" + name);
+                compositeNames.add(createCompositeName(namespace, name));
             }
 
+            String prefix = createPrefix(namespace);
             ArrayMap<String, String> rawKeyValues = sNameValueCache.getStringsForPrefix(
-                    resolver, prefix, concatenatedNames);
+                    resolver, prefix, compositeNames);
             int size = rawKeyValues.size();
-            int substringLength = prefix.length() + 1;
+            int substringLength = prefix.length();
             ArrayMap<String, String> keyValues = new ArrayMap<>(size);
             for (int i = 0; i < size; ++i) {
                 keyValues.put(rawKeyValues.keyAt(i).substring(substringLength),
@@ -13688,7 +13719,7 @@
         }
 
         /**
-         * Store a name/value pair into the database.
+         * Store a name/value pair into the database within the specified namespace.
          * <p>
          * Also the method takes an argument whether to make the value the default for this setting.
          * If the system already specified a default value, then the one passed in here will
@@ -13696,6 +13727,7 @@
          * </p>
          *
          * @param resolver to access the database with.
+         * @param namespace to store the name/value pair in.
          * @param name to store.
          * @param value to associate with the name.
          * @param makeDefault whether to make the value the default one.
@@ -13706,10 +13738,10 @@
          * @hide
          */
         @RequiresPermission(Manifest.permission.WRITE_DEVICE_CONFIG)
-        static boolean putString(@NonNull ContentResolver resolver, @NonNull String name,
-                @Nullable String value, boolean makeDefault) {
-            return sNameValueCache.putStringForUser(resolver, name, value, null, makeDefault,
-                    resolver.getUserId());
+        static boolean putString(@NonNull ContentResolver resolver, @NonNull String namespace,
+                @NonNull String name, @Nullable String value, boolean makeDefault) {
+            return sNameValueCache.putStringForUser(resolver, createCompositeName(namespace, name),
+                    value, null, makeDefault, resolver.getUserId());
         }
 
         /**
@@ -13720,29 +13752,40 @@
          *
          * @param resolver Handle to the content resolver.
          * @param resetMode The reset mode to use.
-         * @param prefix Optionally, to limit which which pairs are reset.
+         * @param namespace Optionally, to limit which which namespace is reset.
          *
-         * @see #putString(ContentResolver, String, String, boolean)
+         * @see #putString(ContentResolver, String, String, String, boolean)
          *
          * @hide
          */
         @RequiresPermission(Manifest.permission.WRITE_DEVICE_CONFIG)
         static void resetToDefaults(@NonNull ContentResolver resolver, @ResetMode int resetMode,
-                @Nullable String prefix) {
+                @Nullable String namespace) {
             try {
                 Bundle arg = new Bundle();
                 arg.putInt(CALL_METHOD_USER_KEY, resolver.getUserId());
                 arg.putInt(CALL_METHOD_RESET_MODE_KEY, resetMode);
-                if (prefix != null) {
-                    arg.putString(Settings.CALL_METHOD_PREFIX_KEY, prefix);
+                if (namespace != null) {
+                    arg.putString(Settings.CALL_METHOD_PREFIX_KEY, createPrefix(namespace));
                 }
                 IContentProvider cp = sProviderHolder.getProvider(resolver);
-                cp.call(resolver.getPackageName(), sProviderHolder.mUri.getAuthority(),
-                        CALL_METHOD_RESET_CONFIG, null, arg);
+                cp.call(resolver.getPackageName(), resolver.getFeatureId(),
+                        sProviderHolder.mUri.getAuthority(), CALL_METHOD_RESET_CONFIG, null, arg);
             } catch (RemoteException e) {
                 Log.w(TAG, "Can't reset to defaults for " + DeviceConfig.CONTENT_URI, e);
             }
         }
+
+        private static String createCompositeName(@NonNull String namespace, @NonNull String name) {
+            Preconditions.checkNotNull(namespace);
+            Preconditions.checkNotNull(name);
+            return createPrefix(namespace) + name;
+        }
+
+        private static String createPrefix(@NonNull String namespace) {
+            Preconditions.checkNotNull(namespace);
+            return namespace + "/";
+        }
     }
 
     /**
diff --git a/core/java/android/provider/SettingsStringUtil.java b/core/java/android/provider/SettingsStringUtil.java
index a3dc947..9e495dd 100644
--- a/core/java/android/provider/SettingsStringUtil.java
+++ b/core/java/android/provider/SettingsStringUtil.java
@@ -126,7 +126,7 @@
 
         @Override
         protected String itemToString(ComponentName item) {
-            return item.flattenToString();
+            return item != null ? item.flattenToString() : "null";
         }
 
         public static String add(String delimitedElements, ComponentName element) {
diff --git a/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java b/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java
new file mode 100644
index 0000000..de90b94
--- /dev/null
+++ b/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java
@@ -0,0 +1,389 @@
+/*
+ * 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.service.carrier;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+
+/**
+ * Provides basic structure for platform to connect to the carrier messaging service.
+ * <p>
+ * <code>
+ * CarrierMessagingServiceWrapper carrierMessagingServiceWrapper =
+ *     new CarrierMessagingServiceWrapperImpl();
+ * if (carrierMessagingServiceWrapper.bindToCarrierMessagingService(context, carrierPackageName)) {
+ *   // wait for onServiceReady callback
+ * } else {
+ *   // Unable to bind: handle error.
+ * }
+ * </code>
+ * <p> Upon completion {@link #disposeConnection} should be called to unbind the
+ * CarrierMessagingService.
+ * @hide
+ */
+@SystemApi
+public abstract class CarrierMessagingServiceWrapper {
+    // Populated by bindToCarrierMessagingService. bindToCarrierMessagingService must complete
+    // prior to calling disposeConnection so that mCarrierMessagingServiceConnection is initialized.
+    private volatile CarrierMessagingServiceConnection mCarrierMessagingServiceConnection;
+
+    private volatile ICarrierMessagingService mICarrierMessagingService;
+
+    /**
+     * Binds to the carrier messaging service under package {@code carrierPackageName}. This method
+     * should be called exactly once.
+     *
+     * @param context the context
+     * @param carrierPackageName the carrier package name
+     * @return true upon successfully binding to a carrier messaging service, false otherwise
+     * @hide
+     */
+    @SystemApi
+    public boolean bindToCarrierMessagingService(@NonNull Context context,
+            @NonNull String carrierPackageName) {
+        Preconditions.checkState(mCarrierMessagingServiceConnection == null);
+
+        Intent intent = new Intent(CarrierMessagingService.SERVICE_INTERFACE);
+        intent.setPackage(carrierPackageName);
+        mCarrierMessagingServiceConnection = new CarrierMessagingServiceConnection();
+        return context.bindService(intent, mCarrierMessagingServiceConnection,
+                Context.BIND_AUTO_CREATE);
+    }
+
+    /**
+     * Unbinds the carrier messaging service. This method should be called exactly once.
+     *
+     * @param context the context
+     * @hide
+     */
+    @SystemApi
+    public void disposeConnection(@NonNull Context context) {
+        Preconditions.checkNotNull(mCarrierMessagingServiceConnection);
+        context.unbindService(mCarrierMessagingServiceConnection);
+        mCarrierMessagingServiceConnection = null;
+    }
+
+    /**
+     * Implemented by subclasses to use the carrier messaging service once it is ready.
+     * @hide
+     */
+    @SystemApi
+    public abstract void onServiceReady();
+
+    /**
+     * Called when connection with service is established.
+     *
+     * @param carrierMessagingService the carrier messaing service interface
+     */
+    private void onServiceReady(ICarrierMessagingService carrierMessagingService) {
+        mICarrierMessagingService = carrierMessagingService;
+        onServiceReady();
+    }
+
+    /**
+     * Request filtering an incoming SMS message.
+     * The service will call callback.onFilterComplete with the filtering result.
+     *
+     * @param pdu the PDUs of the message
+     * @param format the format of the PDUs, typically "3gpp" or "3gpp2"
+     * @param destPort the destination port of a data SMS. It will be -1 for text SMS
+     * @param subId SMS subscription ID of the SIM
+     * @param callback the callback to notify upon completion
+     * @hide
+     */
+    @SystemApi
+    public void filterSms(@NonNull MessagePdu pdu, @NonNull String format, int destPort,
+            int subId, @NonNull final CarrierMessagingCallbackWrapper callback) {
+        if (mICarrierMessagingService != null) {
+            try {
+                mICarrierMessagingService.filterSms(pdu, format, destPort, subId,
+                        new CarrierMessagingCallbackWrapperInternal(callback));
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * Request sending a new text SMS from the device.
+     * The service will call {@link ICarrierMessagingCallback#onSendSmsComplete} with the send
+     * status.
+     *
+     * @param text the text to send
+     * @param subId SMS subscription ID of the SIM
+     * @param destAddress phone number of the recipient of the message
+     * @param sendSmsFlag flag for sending SMS
+     * @param callback the callback to notify upon completion
+     * @hide
+     */
+    @SystemApi
+    public void sendTextSms(@NonNull String text, int subId, @NonNull String destAddress,
+            int sendSmsFlag, @NonNull final CarrierMessagingCallbackWrapper callback) {
+        if (mICarrierMessagingService != null) {
+            try {
+                mICarrierMessagingService.sendTextSms(text, subId, destAddress, sendSmsFlag,
+                        new CarrierMessagingCallbackWrapperInternal(callback));
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * Request sending a new data SMS from the device.
+     * The service will call {@link ICarrierMessagingCallback#onSendSmsComplete} with the send
+     * status.
+     *
+     * @param data the data to send
+     * @param subId SMS subscription ID of the SIM
+     * @param destAddress phone number of the recipient of the message
+     * @param destPort port number of the recipient of the message
+     * @param sendSmsFlag flag for sending SMS
+     * @param callback the callback to notify upon completion
+     * @hide
+     */
+    @SystemApi
+    public void sendDataSms(@NonNull byte[] data, int subId, @NonNull String destAddress,
+            int destPort, int sendSmsFlag,
+            @NonNull final CarrierMessagingCallbackWrapper callback) {
+        if (mICarrierMessagingService != null) {
+            try {
+                mICarrierMessagingService.sendDataSms(data, subId, destAddress, destPort,
+                        sendSmsFlag, new CarrierMessagingCallbackWrapperInternal(callback));
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * Request sending a new multi-part text SMS from the device.
+     * The service will call {@link ICarrierMessagingCallback#onSendMultipartSmsComplete}
+     * with the send status.
+     *
+     * @param parts the parts of the multi-part text SMS to send
+     * @param subId SMS subscription ID of the SIM
+     * @param destAddress phone number of the recipient of the message
+     * @param sendSmsFlag flag for sending SMS
+     * @param callback the callback to notify upon completion
+     * @hide
+     */
+    @SystemApi
+    public void sendMultipartTextSms(@NonNull List<String> parts, int subId,
+            @NonNull String destAddress, int sendSmsFlag,
+            @NonNull final CarrierMessagingCallbackWrapper callback) {
+        if (mICarrierMessagingService != null) {
+            try {
+                mICarrierMessagingService.sendMultipartTextSms(parts, subId, destAddress,
+                        sendSmsFlag, new CarrierMessagingCallbackWrapperInternal(callback));
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * Request sending a new MMS PDU from the device.
+     * The service will call {@link ICarrierMessagingCallback#onSendMmsComplete} with the send
+     * status.
+     *
+     * @param pduUri the content provider URI of the PDU to send
+     * @param subId SMS subscription ID of the SIM
+     * @param location the optional URI to send this MMS PDU. If this is {code null},
+     *        the PDU should be sent to the default MMSC URL.
+     * @param callback the callback to notify upon completion
+     * @hide
+     */
+    @SystemApi
+    public void sendMms(@NonNull Uri pduUri, int subId, @NonNull Uri location,
+            @NonNull final CarrierMessagingCallbackWrapper callback) {
+        if (mICarrierMessagingService != null) {
+            try {
+                mICarrierMessagingService.sendMms(pduUri, subId, location,
+                        new CarrierMessagingCallbackWrapperInternal(callback));
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * Request downloading a new MMS.
+     * The service will call {@link ICarrierMessagingCallback#onDownloadMmsComplete} with the
+     * download status.
+     *
+     * @param pduUri the content provider URI of the PDU to be downloaded.
+     * @param subId SMS subscription ID of the SIM
+     * @param location the URI of the message to be downloaded.
+     * @param callback the callback to notify upon completion
+     * @hide
+     */
+    @SystemApi
+    public void downloadMms(@NonNull Uri pduUri, int subId, @NonNull Uri location,
+            @NonNull final CarrierMessagingCallbackWrapper callback) {
+        if (mICarrierMessagingService != null) {
+            try {
+                mICarrierMessagingService.downloadMms(pduUri, subId, location,
+                        new CarrierMessagingCallbackWrapperInternal(callback));
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * A basic {@link ServiceConnection}.
+     */
+    private final class CarrierMessagingServiceConnection implements ServiceConnection {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            onServiceReady(ICarrierMessagingService.Stub.asInterface(service));
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+        }
+    }
+
+    /**
+     * Callback wrapper used for response to requests exposed by
+     * {@link CarrierMessagingServiceWrapper}.
+     * @hide
+     */
+    @SystemApi
+    public abstract static class CarrierMessagingCallbackWrapper {
+
+        /**
+         * Response callback for {@link CarrierMessagingServiceWrapper#filterSms}.
+         * @param result a bitmask integer to indicate how the incoming text SMS should be handled
+         *               by the platform. Bits set can be
+         *               {@link CarrierMessagingService#RECEIVE_OPTIONS_DROP} and
+         *               {@link CarrierMessagingService#
+         *               RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_PROTECTED_STORAGE_UNAVAILABLE}.
+         *               {@see CarrierMessagingService#onReceiveTextSms}.
+         * @hide
+         */
+        @SystemApi
+        public void onFilterComplete(int result) {
+
+        }
+
+        /**
+         * Response callback for {@link CarrierMessagingServiceWrapper#sendTextSms} and
+         * {@link CarrierMessagingServiceWrapper#sendDataSms}.
+         * @param result send status, one of {@link CarrierMessagingService#SEND_STATUS_OK},
+         *               {@link CarrierMessagingService#SEND_STATUS_RETRY_ON_CARRIER_NETWORK},
+         *               and {@link CarrierMessagingService#SEND_STATUS_ERROR}.
+         * @param messageRef message reference of the just-sent message. This field is applicable
+         *                   only if result is {@link CarrierMessagingService#SEND_STATUS_OK}.
+         * @hide
+         */
+        @SystemApi
+        public void onSendSmsComplete(int result, int messageRef) {
+
+        }
+
+        /**
+         * Response callback for {@link CarrierMessagingServiceWrapper#sendMultipartTextSms}.
+         * @param result send status, one of {@link CarrierMessagingService#SEND_STATUS_OK},
+         *               {@link CarrierMessagingService#SEND_STATUS_RETRY_ON_CARRIER_NETWORK},
+         *               and {@link CarrierMessagingService#SEND_STATUS_ERROR}.
+         * @param messageRefs an array of message references, one for each part of the
+         *                    multipart SMS. This field is applicable only if result is
+         *                    {@link CarrierMessagingService#SEND_STATUS_OK}.
+         * @hide
+         */
+        @SystemApi
+        public void onSendMultipartSmsComplete(int result, @Nullable int[] messageRefs) {
+
+        }
+
+        /**
+         * Response callback for {@link CarrierMessagingServiceWrapper#sendMms}.
+         * @param result send status, one of {@link CarrierMessagingService#SEND_STATUS_OK},
+         *               {@link CarrierMessagingService#SEND_STATUS_RETRY_ON_CARRIER_NETWORK},
+         *               and {@link CarrierMessagingService#SEND_STATUS_ERROR}.
+         * @param sendConfPdu a possibly {code null} SendConf PDU, which confirms that the message
+         *                    was sent. sendConfPdu is ignored if the {@code result} is not
+         *                    {@link CarrierMessagingService#SEND_STATUS_OK}.
+         * @hide
+         */
+        @SystemApi
+        public void onSendMmsComplete(int result, @Nullable byte[] sendConfPdu) {
+
+        }
+
+        /**
+         * Response callback for {@link CarrierMessagingServiceWrapper#downloadMms}.
+         * @param result download status, one of {@link CarrierMessagingService#SEND_STATUS_OK},
+         *               {@link CarrierMessagingService#SEND_STATUS_RETRY_ON_CARRIER_NETWORK},
+         *               and {@link CarrierMessagingService#SEND_STATUS_ERROR}.
+         * @hide
+         */
+        @SystemApi
+        public void onDownloadMmsComplete(int result) {
+
+        }
+    }
+
+    private final class CarrierMessagingCallbackWrapperInternal
+            extends ICarrierMessagingCallback.Stub {
+        CarrierMessagingCallbackWrapper mCarrierMessagingCallbackWrapper;
+
+        CarrierMessagingCallbackWrapperInternal(CarrierMessagingCallbackWrapper callback) {
+            mCarrierMessagingCallbackWrapper = callback;
+        }
+
+        @Override
+        public void onFilterComplete(int result) throws RemoteException {
+            mCarrierMessagingCallbackWrapper.onFilterComplete(result);
+        }
+
+        @Override
+        public void onSendSmsComplete(int result, int messageRef) throws RemoteException {
+            mCarrierMessagingCallbackWrapper.onSendSmsComplete(result, messageRef);
+        }
+
+        @Override
+        public void onSendMultipartSmsComplete(int result, int[] messageRefs)
+                throws RemoteException {
+            mCarrierMessagingCallbackWrapper.onSendMultipartSmsComplete(result, messageRefs);
+        }
+
+        @Override
+        public void onSendMmsComplete(int result, byte[] sendConfPdu) throws RemoteException {
+            mCarrierMessagingCallbackWrapper.onSendMmsComplete(result, sendConfPdu);
+        }
+
+        @Override
+        public void onDownloadMmsComplete(int result) throws RemoteException {
+            mCarrierMessagingCallbackWrapper.onDownloadMmsComplete(result);
+        }
+    }
+}
diff --git a/core/java/android/service/contentsuggestions/ContentSuggestionsService.java b/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
index efc8e87..4bcd39f 100644
--- a/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
+++ b/core/java/android/service/contentsuggestions/ContentSuggestionsService.java
@@ -66,12 +66,17 @@
                 int colorSpaceId, Bundle imageContextRequestExtras) {
 
             Bitmap wrappedBuffer = null;
-            if (contextImage != null) {
-                ColorSpace colorSpace = null;
-                if (colorSpaceId >= 0 && colorSpaceId < ColorSpace.Named.values().length) {
-                    colorSpace = ColorSpace.get(ColorSpace.Named.values()[colorSpaceId]);
+            if (imageContextRequestExtras.containsKey(ContentSuggestionsManager.EXTRA_BITMAP)) {
+                wrappedBuffer = imageContextRequestExtras.getParcelable(
+                        ContentSuggestionsManager.EXTRA_BITMAP);
+            } else {
+                if (contextImage != null) {
+                    ColorSpace colorSpace = null;
+                    if (colorSpaceId >= 0 && colorSpaceId < ColorSpace.Named.values().length) {
+                        colorSpace = ColorSpace.get(ColorSpace.Named.values()[colorSpaceId]);
+                    }
+                    wrappedBuffer = Bitmap.wrapHardwareBuffer(contextImage, colorSpace);
                 }
-                wrappedBuffer = Bitmap.wrapHardwareBuffer(contextImage, colorSpace);
             }
 
             mHandler.sendMessage(
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index 8a9f689..12c2580 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -516,7 +516,7 @@
      * @see android.telephony.euicc.EuiccManager#eraseSubscriptions
      *
      * @deprecated From R, callers should specify a flag for specific set of subscriptions to erase
-     * and use @link{onEraseSubscriptionsWithOptions} instead
+     * and use {@link #onEraseSubscriptionsWithOptions(int, int)} instead
      */
     @Deprecated
     public abstract int onEraseSubscriptions(int slotId);
diff --git a/core/java/android/service/textclassifier/ITextClassifierService.aidl b/core/java/android/service/textclassifier/ITextClassifierService.aidl
index 2f8d67b..da57506 100644
--- a/core/java/android/service/textclassifier/ITextClassifierService.aidl
+++ b/core/java/android/service/textclassifier/ITextClassifierService.aidl
@@ -74,4 +74,6 @@
             in TextClassificationSessionId sessionId,
             in ConversationActions.Request request,
             in ITextClassifierCallback callback);
+
+    void onConnectedStateChanged(int connected);
 }
diff --git a/core/java/android/service/textclassifier/TextClassifierService.java b/core/java/android/service/textclassifier/TextClassifierService.java
index 2470d19..4d58ae4 100644
--- a/core/java/android/service/textclassifier/TextClassifierService.java
+++ b/core/java/android/service/textclassifier/TextClassifierService.java
@@ -17,6 +17,7 @@
 package android.service.textclassifier;
 
 import android.Manifest;
+import android.annotation.IntDef;
 import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -51,6 +52,8 @@
 
 import com.android.internal.util.Preconditions;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
@@ -99,6 +102,18 @@
             "android.service.textclassifier.TextClassifierService";
 
     /** @hide **/
+    public static final int CONNECTED = 0;
+    /** @hide **/
+    public static final int DISCONNECTED = 1;
+    /** @hide */
+    @IntDef(value = {
+            CONNECTED,
+            DISCONNECTED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ConnectionState{}
+
+    /** @hide **/
     private static final String KEY_RESULT = "key_result";
 
     private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper(), null, true);
@@ -195,6 +210,12 @@
             mMainThreadHandler.post(
                     () -> TextClassifierService.this.onDestroyTextClassificationSession(sessionId));
         }
+
+        @Override
+        public void onConnectedStateChanged(@ConnectionState int connected) {
+            mMainThreadHandler.post(connected == CONNECTED ? TextClassifierService.this::onConnected
+                    : TextClassifierService.this::onDisconnected);
+        }
     };
 
     @Nullable
@@ -206,6 +227,26 @@
         return null;
     }
 
+    @Override
+    public boolean onUnbind(@NonNull Intent intent) {
+        onDisconnected();
+        return super.onUnbind(intent);
+    }
+
+    /**
+     * Called when the Android system connects to service.
+     */
+    public void onConnected() {
+    }
+
+    /**
+     * Called when the Android system disconnects from the service.
+     *
+     * <p> At this point this service may no longer be an active {@link TextClassifierService}.
+     */
+    public void onDisconnected() {
+    }
+
     /**
      * Returns suggested text selection start and end indices, recognized entity types, and their
      * associated confidence scores. The entity types are ordered from highest to lowest scoring.
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 94f6a50..cf56eae 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -20,7 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
-import android.app.Activity;
+import android.content.Context;
 import android.content.Intent;
 import android.hardware.soundtrigger.IRecognitionStatusCallback;
 import android.hardware.soundtrigger.KeyphraseEnrollmentInfo;
@@ -446,7 +446,7 @@
 
     /**
      * Creates an intent to start the enrollment for the associated keyphrase.
-     * This intent must be invoked using {@link Activity#startActivityForResult(Intent, int)}.
+     * This intent must be invoked using {@link Context#startForegroundService(Intent)}.
      * Starting re-enrollment is only valid if the keyphrase is un-enrolled,
      * i.e. {@link #STATE_KEYPHRASE_UNENROLLED},
      * otherwise {@link #createReEnrollIntent()} should be preferred.
@@ -468,7 +468,7 @@
 
     /**
      * Creates an intent to start the un-enrollment for the associated keyphrase.
-     * This intent must be invoked using {@link Activity#startActivityForResult(Intent, int)}.
+     * This intent must be invoked using {@link Context#startForegroundService(Intent)}.
      * Starting re-enrollment is only valid if the keyphrase is already enrolled,
      * i.e. {@link #STATE_KEYPHRASE_ENROLLED}, otherwise invoking this may result in an error.
      *
@@ -489,7 +489,7 @@
 
     /**
      * Creates an intent to start the re-enrollment for the associated keyphrase.
-     * This intent must be invoked using {@link Activity#startActivityForResult(Intent, int)}.
+     * This intent must be invoked using {@link Context#startForegroundService(Intent)}.
      * Starting re-enrollment is only valid if the keyphrase is already enrolled,
      * i.e. {@link #STATE_KEYPHRASE_ENROLLED}, otherwise invoking this may result in an error.
      *
diff --git a/core/java/android/speech/IRecognitionService.aidl b/core/java/android/speech/IRecognitionService.aidl
index be6ef6d..f91e122 100644
--- a/core/java/android/speech/IRecognitionService.aidl
+++ b/core/java/android/speech/IRecognitionService.aidl
@@ -39,8 +39,11 @@
      *        this intent can contain extra parameters to manipulate the behavior of the recognition
      *        client. For more information see {@link RecognizerIntent}.
      * @param listener to receive callbacks, note that this must be non-null
+     * @param packageName the package name calling this API
+     * @param featureId The feature in the package
      */
-    void startListening(in Intent recognizerIntent, in IRecognitionListener listener);
+    void startListening(in Intent recognizerIntent, in IRecognitionListener listener,
+            String packageName, String featureId);
 
     /**
      * Stops listening for speech. Speech captured so far will be recognized as
@@ -48,13 +51,17 @@
      * is called during the speech capturing.
      *
      * @param listener to receive callbacks, note that this must be non-null
+     * @param packageName the package name calling this API
+     * @param featureId The feature in the package
      */
-    void stopListening(in IRecognitionListener listener);
+    void stopListening(in IRecognitionListener listener, String packageName, String featureId);
 
     /**
      * Cancels the speech recognition.
      *
      * @param listener to receive callbacks, note that this must be non-null
+     * @param packageName the package name calling this API
+     * @param featureId The feature in the package
      */
-    void cancel(in IRecognitionListener listener);
+    void cancel(in IRecognitionListener listener, String packageName, String featureId);
 }
diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java
index dfc5c82..4b42209 100644
--- a/core/java/android/speech/RecognitionService.java
+++ b/core/java/android/speech/RecognitionService.java
@@ -16,6 +16,8 @@
 
 package android.speech;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.Service;
@@ -29,6 +31,8 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.internal.util.Preconditions;
+
 import java.lang.ref.WeakReference;
 
 /**
@@ -171,13 +175,17 @@
      * 
      * @param listener to send the error message to in case of error
      * @param forDataDelivery If the permission check is for delivering the sensitive data.
+     * @param packageName the package name of the caller
+     * @param featureId The feature in the package
      * @return {@code true} if the caller has enough permissions, {@code false} otherwise
      */
-    private boolean checkPermissions(IRecognitionListener listener, boolean forDataDelivery) {
+    private boolean checkPermissions(IRecognitionListener listener, boolean forDataDelivery,
+            @NonNull String packageName, @Nullable String featureId) {
         if (DBG) Log.d(TAG, "checkPermissions");
         if (forDataDelivery) {
-            if (PermissionChecker.checkCallingOrSelfPermissionForDataDelivery(this,
-                    android.Manifest.permission.RECORD_AUDIO, null /*message*/)
+            if (PermissionChecker.checkCallingPermissionForDataDelivery(this,
+                    android.Manifest.permission.RECORD_AUDIO, packageName, featureId,
+                    null /*message*/)
                              == PermissionChecker.PERMISSION_GRANTED) {
                 return true;
             }
@@ -349,10 +357,14 @@
         }
 
         @Override
-        public void startListening(Intent recognizerIntent, IRecognitionListener listener) {
+        public void startListening(Intent recognizerIntent, IRecognitionListener listener,
+                String packageName, String featureId) {
+            Preconditions.checkNotNull(packageName);
+
             if (DBG) Log.d(TAG, "startListening called by:" + listener.asBinder());
             final RecognitionService service = mServiceRef.get();
-            if (service != null && service.checkPermissions(listener, true /*forDataDelivery*/)) {
+            if (service != null && service.checkPermissions(listener, true /*forDataDelivery*/,
+                    packageName, featureId)) {
                 service.mHandler.sendMessage(Message.obtain(service.mHandler,
                         MSG_START_LISTENING, service.new StartListeningArgs(
                                 recognizerIntent, listener, Binder.getCallingUid())));
@@ -360,20 +372,28 @@
         }
 
         @Override
-        public void stopListening(IRecognitionListener listener) {
+        public void stopListening(IRecognitionListener listener, String packageName,
+                String featureId) {
+            Preconditions.checkNotNull(packageName);
+
             if (DBG) Log.d(TAG, "stopListening called by:" + listener.asBinder());
             final RecognitionService service = mServiceRef.get();
-            if (service != null && service.checkPermissions(listener, false /*forDataDelivery*/)) {
+            if (service != null && service.checkPermissions(listener, false /*forDataDelivery*/,
+                    packageName, featureId)) {
                 service.mHandler.sendMessage(Message.obtain(service.mHandler,
                         MSG_STOP_LISTENING, listener));
             }
         }
 
         @Override
-        public void cancel(IRecognitionListener listener) {
+        public void cancel(IRecognitionListener listener, String packageName,
+                String featureId) {
+            Preconditions.checkNotNull(packageName);
+
             if (DBG) Log.d(TAG, "cancel called by:" + listener.asBinder());
             final RecognitionService service = mServiceRef.get();
-            if (service != null && service.checkPermissions(listener, false /*forDataDelivery*/)) {
+            if (service != null && service.checkPermissions(listener, false /*forDataDelivery*/,
+                    packageName, featureId)) {
                 service.mHandler.sendMessage(Message.obtain(service.mHandler,
                         MSG_CANCEL, listener));
             }
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index 88e2ede..e93ba16 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -341,7 +341,8 @@
             return;
         }
         try {
-            mService.startListening(recognizerIntent, mListener);
+            mService.startListening(recognizerIntent, mListener, mContext.getOpPackageName(),
+                    mContext.getFeatureId());
             if (DBG) Log.d(TAG, "service start listening command succeded");
         } catch (final RemoteException e) {
             Log.e(TAG, "startListening() failed", e);
@@ -355,7 +356,8 @@
             return;
         }
         try {
-            mService.stopListening(mListener);
+            mService.stopListening(mListener, mContext.getOpPackageName(),
+                    mContext.getFeatureId());
             if (DBG) Log.d(TAG, "service stop listening command succeded");
         } catch (final RemoteException e) {
             Log.e(TAG, "stopListening() failed", e);
@@ -369,7 +371,7 @@
             return;
         }
         try {
-            mService.cancel(mListener);
+            mService.cancel(mListener, mContext.getOpPackageName(), mContext.getFeatureId());
             if (DBG) Log.d(TAG, "service cancel command succeded");
         } catch (final RemoteException e) {
             Log.e(TAG, "cancel() failed", e);
@@ -398,7 +400,7 @@
     public void destroy() {
         if (mService != null) {
             try {
-                mService.cancel(mListener);
+                mService.cancel(mListener, mContext.getOpPackageName(), mContext.getFeatureId());
             } catch (final RemoteException e) {
                 // Not important
             }
diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java
index e78b796..73e17a6 100644
--- a/core/java/android/util/LongSparseArray.java
+++ b/core/java/android/util/LongSparseArray.java
@@ -17,7 +17,6 @@
 package android.util;
 
 import android.os.Parcel;
-import android.os.Parcelable;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.GrowingArrayUtils;
@@ -25,6 +24,8 @@
 
 import libcore.util.EmptyArray;
 
+import java.util.Arrays;
+
 /**
  * SparseArray mapping longs to Objects.  Unlike a normal array of Objects,
  * there can be gaps in the indices.  It is intended to be more memory efficient
@@ -450,22 +451,25 @@
     /**
      * @hide
      */
-    public static class StringParcelling implements com.android.internal.util.Parcelling {
+    public static class StringParcelling implements
+            com.android.internal.util.Parcelling<LongSparseArray<String>> {
         @Override
-        public void parcel(Object item, Parcel dest, int parcelFlags) {
-            if (item == null) {
+        public void parcel(LongSparseArray<String> array, Parcel dest, int parcelFlags) {
+            if (array == null) {
                 dest.writeInt(-1);
                 return;
             }
 
-            LongSparseArray<String> array = (LongSparseArray<String>) item;
-            dest.writeInt(array.mSize);
+            int size = array.mSize;
+
+            dest.writeInt(size);
             dest.writeLongArray(array.mKeys);
-            dest.writeStringArray((String[]) array.mValues);
+
+            dest.writeStringArray(Arrays.copyOfRange(array.mValues, 0, size, String[].class));
         }
 
         @Override
-        public Object unparcel(Parcel source) {
+        public LongSparseArray<String> unparcel(Parcel source) {
             int size = source.readInt();
             if (size == -1) {
                 return null;
@@ -490,49 +494,4 @@
             return array;
         }
     }
-
-    /**
-     * @hide
-     */
-    public static class Parcelling<T extends Parcelable> implements
-            com.android.internal.util.Parcelling {
-        @Override
-        public void parcel(Object item, Parcel dest, int parcelFlags) {
-            if (item == null) {
-                dest.writeInt(-1);
-                return;
-            }
-
-            LongSparseArray<T> array = (LongSparseArray<T>) item;
-            dest.writeInt(array.mSize);
-            dest.writeLongArray(array.mKeys);
-            dest.writeParcelableArray((T[]) array.mValues, parcelFlags);
-        }
-
-        @Override
-        public Object unparcel(Parcel source) {
-            int size = source.readInt();
-            if (size == -1) {
-                return null;
-            }
-
-            LongSparseArray<T> array = new LongSparseArray<>(0);
-            array.mSize = size;
-            array.mKeys = source.createLongArray();
-            array.mValues = source.readParcelableArray(null);
-
-            // Make sure array is sane
-            Preconditions.checkArgument(array.mKeys.length >= size);
-            Preconditions.checkArgument(array.mValues.length >= size);
-
-            if (size > 0) {
-                long last = array.mKeys[0];
-                for (int i = 1; i < size; i++) {
-                    Preconditions.checkArgument(last < array.mKeys[i]);
-                }
-            }
-
-            return array;
-        }
-    }
 }
diff --git a/core/java/android/util/LongSparseLongArray.java b/core/java/android/util/LongSparseLongArray.java
index 9ffd4f0..a0edd04 100644
--- a/core/java/android/util/LongSparseLongArray.java
+++ b/core/java/android/util/LongSparseLongArray.java
@@ -289,22 +289,22 @@
     /**
      * @hide
      */
-    public static class Parcelling implements com.android.internal.util.Parcelling {
+    public static class Parcelling implements
+            com.android.internal.util.Parcelling<LongSparseLongArray> {
         @Override
-        public void parcel(Object item, Parcel dest, int parcelFlags) {
-            if (item == null) {
+        public void parcel(LongSparseLongArray array, Parcel dest, int parcelFlags) {
+            if (array == null) {
                 dest.writeInt(-1);
                 return;
             }
 
-            LongSparseLongArray array = (LongSparseLongArray) item;
             dest.writeInt(array.mSize);
             dest.writeLongArray(array.mKeys);
             dest.writeLongArray(array.mValues);
         }
 
         @Override
-        public Object unparcel(Parcel source) {
+        public LongSparseLongArray unparcel(Parcel source) {
             int size = source.readInt();
             if (size == -1) {
                 return null;
diff --git a/core/java/android/util/StatsEvent.java b/core/java/android/util/StatsEvent.java
index 91a5ec0..8d9607f 100644
--- a/core/java/android/util/StatsEvent.java
+++ b/core/java/android/util/StatsEvent.java
@@ -20,312 +20,540 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.os.SystemClock;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 
 /**
  * StatsEvent builds and stores the buffer sent over the statsd socket.
  * This class defines and encapsulates the socket protocol.
+ *
+ * <p>Usage:</p>
+ * <pre>
+ *      StatsEvent statsEvent = StatsEvent.newBuilder()
+ *          .setAtomId(atomId)
+ *          .writeBoolean(false)
+ *          .writeString("annotated String field")
+ *          .addBooleanAnnotation(annotationId, true)
+ *          .build();
+ *
+ *      StatsLog.write(statsEvent);
+ * </pre>
  * @hide
  **/
-public final class StatsEvent implements AutoCloseable {
-    private static final int POS_NUM_ELEMENTS = 1;
-    private static final int POS_TIMESTAMP = POS_NUM_ELEMENTS + 1;
-
+public final class StatsEvent {
     private static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068;
 
-    // Max payload size is 4 KB less 4 bytes which are reserved for statsEventTag.
+    // Max payload size is 4 bytes less as 4 bytes are reserved for statsEventTag.
     // See android_util_StatsLog.cpp.
-    private static final int MAX_EVENT_PAYLOAD = LOGGER_ENTRY_MAX_PAYLOAD - 4;
+    private static final int MAX_PAYLOAD_SIZE = LOGGER_ENTRY_MAX_PAYLOAD - 4;
 
-    private static final byte INT_TYPE = 0;
-    private static final byte LONG_TYPE = 1;
-    private static final byte STRING_TYPE = 2;
-    private static final byte LIST_TYPE = 3;
-    private static final byte FLOAT_TYPE = 4;
+    private final Buffer mBuffer;
+    private final int mNumBytes;
 
-    private static final int INT_TYPE_SIZE = 5;
-    private static final int FLOAT_TYPE_SIZE = 5;
-    private static final int LONG_TYPE_SIZE = 9;
-
-    private static final int STRING_TYPE_OVERHEAD = 5;
-    private static final int LIST_TYPE_OVERHEAD = 2;
-
-    public static final int SUCCESS = 0;
-    public static final int ERROR_BUFFER_LIMIT_EXCEEDED = -1;
-    public static final int ERROR_NO_TIMESTAMP = -2;
-    public static final int ERROR_TIMESTAMP_ALREADY_WRITTEN = -3;
-    public static final int ERROR_NO_ATOM_ID = -4;
-    public static final int ERROR_ATOM_ID_ALREADY_WRITTEN = -5;
-    public static final int ERROR_UID_TAG_COUNT_MISMATCH = -6;
-
-    private static Object sLock = new Object();
-
-    @GuardedBy("sLock")
-    private static StatsEvent sPool;
-
-    private final byte[] mBuffer = new byte[MAX_EVENT_PAYLOAD];
-    private int mPos;
-    private int mNumElements;
-    private int mAtomId;
-
-    private StatsEvent() {
-        // Write LIST_TYPE to buffer
-        mBuffer[0] = LIST_TYPE;
-        reset();
-    }
-
-    private void reset() {
-        // Reset state.
-        mPos = POS_TIMESTAMP;
-        mNumElements = 0;
-        mAtomId = 0;
+    private StatsEvent(@NonNull final Buffer buffer, final int numBytes) {
+        mBuffer = buffer;
+        mNumBytes = numBytes;
     }
 
     /**
-     * Returns a StatsEvent object from the pool.
+     * Returns a new StatsEvent.Builder for building StatsEvent object.
      **/
     @NonNull
-    public static StatsEvent obtain() {
-        final StatsEvent statsEvent;
-        synchronized (sLock) {
-            statsEvent = null == sPool ? new StatsEvent() : sPool;
-            sPool = null;
-        }
-        statsEvent.reset();
-        return statsEvent;
+    public StatsEvent.Builder newBuilder() {
+        return new StatsEvent.Builder(Buffer.obtain());
     }
 
-    @Override
-    public void close() {
-        synchronized (sLock) {
-            if (null == sPool) {
-                sPool = this;
-            }
-        }
+    @NonNull
+    byte[] getBytes() {
+        return mBuffer.getBytes();
+    }
+
+    int getNumBytes() {
+        return mNumBytes;
+    }
+
+    void release() {
+        mBuffer.release();
     }
 
     /**
-     * Writes the event timestamp to the buffer.
+     * Builder for constructing a StatsEvent object.
+     *
+     * <p>This class defines and encapsulates the socket encoding for the buffer.
+     * The write methods must be called in the same order as the order of fields in the
+     * atom definition.</p>
+     *
+     * <p>setAtomId() can be called anytime before build().</p>
+     *
+     * <p>Example:</p>
+     * <pre>
+     *     // Atom definition.
+     *     message MyAtom {
+     *         optional int32 field1 = 1;
+     *         optional int64 field2 = 2;
+     *         optional string field3 = 3 [(annotation1) = true];
+     *     }
+     *
+     *     // StatsEvent construction.
+     *     StatsEvent.newBuilder()
+     *     StatsEvent statsEvent = StatsEvent.newBuilder()
+     *         .setAtomId(atomId)
+     *         .writeInt(3) // field1
+     *         .writeLong(8L) // field2
+     *         .writeString("foo") // field 3
+     *         .addBooleanAnnotation(annotation1Id, true)
+     *         .build();
+     * </pre>
+     * @hide
      **/
-    public int writeTimestampNs(final long timestampNs) {
-        if (hasTimestamp()) {
-            return ERROR_TIMESTAMP_ALREADY_WRITTEN;
-        }
-        return writeLong(timestampNs);
-    }
+    public static final class Builder {
+        // Type Ids.
+        private static final byte TYPE_INT = 0x00;
+        private static final byte TYPE_LONG = 0x01;
+        private static final byte TYPE_STRING = 0x02;
+        private static final byte TYPE_LIST = 0x03;
+        private static final byte TYPE_FLOAT = 0x04;
+        private static final byte TYPE_BOOLEAN = 0x05;
+        private static final byte TYPE_OBJECT = 0x06;
+        private static final byte TYPE_BYTE_ARRAY = 0x07;
+        private static final byte TYPE_ATTRIBUTION_CHAIN = 0x08;
+        private static final byte TYPE_ERRORS = 0x0F;
 
-    private boolean hasTimestamp() {
-        return mPos > POS_TIMESTAMP;
-    }
+        // Error flags.
+        private static final int ERROR_NO_TIMESTAMP = 0x1;
+        private static final int ERROR_NO_ATOM_ID = 0x2;
+        private static final int ERROR_OVERFLOW = 0x4;
+        private static final int ERROR_ATTRIBUTION_CHAIN_TOO_LONG = 0x8;
+        private static final int ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD = 0x10;
+        private static final int ERROR_INVALID_ANNOTATION_ID = 0x20;
+        private static final int ERROR_ANNOTATION_ID_TOO_LARGE = 0x40;
+        private static final int ERROR_TOO_MANY_ANNOTATIONS = 0x80;
+        private static final int ERROR_TOO_MANY_FIELDS = 0x100;
+        private static final int ERROR_ATTRIBUTION_UIDS_TAGS_SIZES_NOT_EQUAL = 0x200;
 
-    private boolean hasAtomId() {
-        return mAtomId != 0;
-    }
+        // Size limits.
+        private static final int MAX_ANNOTATION_COUNT = 15;
+        private static final int MAX_ATTRIBUTION_NODES = 127;
+        private static final int MAX_NUM_ELEMENTS = 127;
 
-    /**
-     * Writes the atom id to the buffer.
-     **/
-    public int writeAtomId(final int atomId) {
-        if (!hasTimestamp()) {
-            return ERROR_NO_TIMESTAMP;
-        } else if (hasAtomId()) {
-            return ERROR_ATOM_ID_ALREADY_WRITTEN;
+        // Fixed positions.
+        private static final int POS_NUM_ELEMENTS = 1;
+        private static final int POS_TIMESTAMP_NS = POS_NUM_ELEMENTS + Byte.BYTES;
+        private static final int POS_ATOM_ID = POS_TIMESTAMP_NS + Byte.BYTES + Long.BYTES;
+
+        private final Buffer mBuffer;
+        private long mTimestampNs;
+        private int mAtomId;
+        private byte mCurrentAnnotationCount;
+        private int mPos;
+        private int mPosLastField;
+        private byte mLastType;
+        private int mNumElements;
+        private int mErrorMask;
+
+        private Builder(final Buffer buffer) {
+            mBuffer = buffer;
+            mCurrentAnnotationCount = 0;
+            mAtomId = 0;
+            mTimestampNs = SystemClock.elapsedRealtimeNanos();
+            mNumElements = 0;
+
+            // Set mPos to 0 for writing TYPE_OBJECT at 0th position.
+            mPos = 0;
+            writeTypeId(TYPE_OBJECT);
+
+            // Set mPos to after atom id's location in the buffer.
+            // First 2 elements in the buffer are event timestamp followed by the atom id.
+            mPos = POS_ATOM_ID + Byte.BYTES + Integer.BYTES;
+            mPosLastField = 0;
+            mLastType = 0;
         }
 
-        final int writeResult = writeInt(atomId);
-        if (SUCCESS == writeResult) {
+        /**
+         * Sets the atom id for this StatsEvent.
+         **/
+        @NonNull
+        public Builder setAtomId(final int atomId) {
             mAtomId = atomId;
-        }
-        return writeResult;
-    }
-
-    /**
-     * Appends the given int to the StatsEvent buffer.
-     **/
-    public int writeInt(final int value) {
-        if (!hasTimestamp()) {
-            return ERROR_NO_TIMESTAMP;
-        } else if (!hasAtomId()) {
-            return ERROR_NO_ATOM_ID;
-        } else if (mPos + INT_TYPE_SIZE > MAX_EVENT_PAYLOAD) {
-            return ERROR_BUFFER_LIMIT_EXCEEDED;
+            return this;
         }
 
-        mBuffer[mPos] = INT_TYPE;
-        copyInt(mBuffer, mPos + 1, value);
-        mPos += INT_TYPE_SIZE;
-        mNumElements++;
-        return SUCCESS;
-    }
-
-    /**
-     * Appends the given long to the StatsEvent buffer.
-     **/
-    public int writeLong(final long value) {
-        if (!hasTimestamp()) {
-            return ERROR_NO_TIMESTAMP;
-        } else if (!hasAtomId()) {
-            return ERROR_NO_ATOM_ID;
-        } else if (mPos + LONG_TYPE_SIZE > MAX_EVENT_PAYLOAD) {
-            return ERROR_BUFFER_LIMIT_EXCEEDED;
+        /**
+         * Sets the timestamp in nanos for this StatsEvent.
+         **/
+        @VisibleForTesting
+        @NonNull
+        public Builder setTimestampNs(final long timestampNs) {
+            mTimestampNs = timestampNs;
+            return this;
         }
 
-        mBuffer[mPos] = LONG_TYPE;
-        copyLong(mBuffer, mPos + 1, value);
-        mPos += LONG_TYPE_SIZE;
-        mNumElements++;
-        return SUCCESS;
-    }
-
-    /**
-     * Appends the given float to the StatsEvent buffer.
-     **/
-    public int writeFloat(final float value) {
-        if (!hasTimestamp()) {
-            return ERROR_NO_TIMESTAMP;
-        } else if (!hasAtomId()) {
-            return ERROR_NO_ATOM_ID;
-        } else if (mPos + FLOAT_TYPE_SIZE > MAX_EVENT_PAYLOAD) {
-            return ERROR_BUFFER_LIMIT_EXCEEDED;
+        /**
+         * Write a boolean field to this StatsEvent.
+         **/
+        @NonNull
+        public Builder writeBoolean(final boolean value) {
+            // Write boolean typeId byte followed by boolean byte representation.
+            writeTypeId(TYPE_BOOLEAN);
+            mPos += mBuffer.putBoolean(mPos, value);
+            mNumElements++;
+            return this;
         }
 
-        mBuffer[mPos] = FLOAT_TYPE;
-        copyInt(mBuffer, mPos + 1, Float.floatToIntBits(value));
-        mPos += FLOAT_TYPE_SIZE;
-        mNumElements++;
-        return SUCCESS;
-    }
-
-    /**
-     * Appends the given boolean to the StatsEvent buffer.
-     **/
-    public int writeBoolean(final boolean value) {
-        return writeInt(value ? 1 : 0);
-    }
-
-    /**
-     * Appends the given byte array to the StatsEvent buffer.
-     **/
-    public int writeByteArray(@NonNull final byte[] value) {
-        if (!hasTimestamp()) {
-            return ERROR_NO_TIMESTAMP;
-        } else if (!hasAtomId()) {
-            return ERROR_NO_ATOM_ID;
-        } else if (mPos + STRING_TYPE_OVERHEAD + value.length > MAX_EVENT_PAYLOAD) {
-            return ERROR_BUFFER_LIMIT_EXCEEDED;
+        /**
+         * Write an integer field to this StatsEvent.
+         **/
+        @NonNull
+        public Builder writeInt(final int value) {
+            // Write integer typeId byte followed by 4-byte representation of value.
+            writeTypeId(TYPE_INT);
+            mPos += mBuffer.putInt(mPos, value);
+            mNumElements++;
+            return this;
         }
 
-        mBuffer[mPos] = STRING_TYPE;
-        copyInt(mBuffer, mPos + 1, value.length);
-        System.arraycopy(value, 0, mBuffer, mPos + STRING_TYPE_OVERHEAD, value.length);
-        mPos += STRING_TYPE_OVERHEAD + value.length;
-        mNumElements++;
-        return SUCCESS;
-    }
-
-    /**
-     * Appends the given String to the StatsEvent buffer.
-     **/
-    public int writeString(@NonNull final String value) {
-        final byte[] valueBytes = stringToBytes(value);
-        return writeByteArray(valueBytes);
-    }
-
-    /**
-     * Appends the AttributionNode specified as array of uids and array of tags.
-     **/
-    public int writeAttributionNode(@NonNull final int[] uids, @NonNull final String[] tags) {
-        if (!hasTimestamp()) {
-            return ERROR_NO_TIMESTAMP;
-        } else if (!hasAtomId()) {
-            return ERROR_NO_ATOM_ID;
-        } else if (mPos + LIST_TYPE_OVERHEAD > MAX_EVENT_PAYLOAD) {
-            return ERROR_BUFFER_LIMIT_EXCEEDED;
+        /**
+         * Write a long field to this StatsEvent.
+         **/
+        @NonNull
+        public Builder writeLong(final long value) {
+            // Write long typeId byte followed by 8-byte representation of value.
+            writeTypeId(TYPE_LONG);
+            mPos += mBuffer.putLong(mPos, value);
+            mNumElements++;
+            return this;
         }
 
-        final int numTags = tags.length;
-        final int numUids = uids.length;
-        if (numTags != numUids) {
-            return ERROR_UID_TAG_COUNT_MISMATCH;
+        /**
+         * Write a float field to this StatsEvent.
+         **/
+        @NonNull
+        public Builder writeFloat(final float value) {
+            // Write float typeId byte followed by 4-byte representation of value.
+            writeTypeId(TYPE_FLOAT);
+            mPos += mBuffer.putFloat(mPos, value);
+            mNumElements++;
+            return this;
         }
 
-        int pos = mPos;
-        mBuffer[pos] = LIST_TYPE;
-        mBuffer[pos + 1] = (byte) numTags;
-        pos += LIST_TYPE_OVERHEAD;
-        for (int i = 0; i < numTags; i++) {
-            final byte[] tagBytes = stringToBytes(tags[i]);
+        /**
+         * Write a String field to this StatsEvent.
+         **/
+        @NonNull
+        public Builder writeString(@NonNull final String value) {
+            // Write String typeId byte, followed by 4-byte representation of number of bytes
+            // in the UTF-8 encoding, followed by the actual UTF-8 byte encoding of value.
+            final byte[] valueBytes = stringToBytes(value);
+            writeByteArray(valueBytes, TYPE_STRING);
+            return this;
+        }
 
-            if (pos + LIST_TYPE_OVERHEAD + INT_TYPE_SIZE
-                    + STRING_TYPE_OVERHEAD + tagBytes.length > MAX_EVENT_PAYLOAD) {
-                return ERROR_BUFFER_LIMIT_EXCEEDED;
+        /**
+         * Write a byte array field to this StatsEvent.
+         **/
+        @NonNull
+        public Builder writeByteArray(@NonNull final byte[] value) {
+            // Write byte array typeId byte, followed by 4-byte representation of number of bytes
+            // in value, followed by the actual byte array.
+            writeByteArray(value, TYPE_BYTE_ARRAY);
+            return this;
+        }
+
+        private void writeByteArray(@NonNull final byte[] value, final byte typeId) {
+            writeTypeId(typeId);
+            final int numBytes = value.length;
+            mPos += mBuffer.putInt(mPos, numBytes);
+            mPos += mBuffer.putByteArray(mPos, value);
+            mNumElements++;
+        }
+
+        /**
+         * Write an attribution chain field to this StatsEvent.
+         *
+         * The sizes of uids and tags must be equal. The AttributionNode at position i is
+         * made up of uids[i] and tags[i].
+         *
+         * @param uids array of uids in the attribution nodes.
+         * @param tags array of tags in the attribution nodes.
+         **/
+        @NonNull
+        public Builder writeAttributionNode(
+                @NonNull final int[] uids, @NonNull final String[] tags) {
+            final byte numUids = (byte) uids.length;
+            final byte numTags = (byte) tags.length;
+
+            if (numUids != numTags) {
+                mErrorMask |= ERROR_ATTRIBUTION_UIDS_TAGS_SIZES_NOT_EQUAL;
+            } else if (numUids > MAX_ATTRIBUTION_NODES) {
+                mErrorMask |= ERROR_ATTRIBUTION_CHAIN_TOO_LONG;
+            } else {
+                // Write attribution chain typeId byte, followed by 1-byte representation of
+                // number of attribution nodes, followed by encoding of each attribution node.
+                writeTypeId(TYPE_ATTRIBUTION_CHAIN);
+                mPos += mBuffer.putByte(mPos, numUids);
+                for (int i = 0; i < numUids; i++) {
+                    // Each uid is encoded as 4-byte representation of its int value.
+                    mPos += mBuffer.putInt(mPos, uids[i]);
+
+                    // Each tag is encoded as 4-byte representation of number of bytes in its
+                    // UTF-8 encoding, followed by the actual UTF-8 bytes.
+                    final byte[] tagBytes = stringToBytes(tags[i]);
+                    mPos += mBuffer.putInt(mPos, tagBytes.length);
+                    mPos += mBuffer.putByteArray(mPos, tagBytes);
+                }
+                mNumElements++;
+            }
+            return this;
+        }
+
+        /**
+         * Write a boolean annotation for the last field written.
+         **/
+        @NonNull
+        public Builder addBooleanAnnotation(
+                final byte annotationId, final boolean value) {
+            // Ensure there's a field written to annotate.
+            if (0 == mPosLastField) {
+                mErrorMask |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
+            } else if (mCurrentAnnotationCount >= MAX_ANNOTATION_COUNT) {
+                mErrorMask |= ERROR_TOO_MANY_ANNOTATIONS;
+            } else {
+                mPos += mBuffer.putByte(mPos, annotationId);
+                mPos += mBuffer.putByte(mPos, TYPE_BOOLEAN);
+                mPos += mBuffer.putBoolean(mPos, value);
+                mCurrentAnnotationCount++;
+                writeAnnotationCount();
+            }
+            return this;
+        }
+
+        /**
+         * Write an integer annotation for the last field written.
+         **/
+        @NonNull
+        public Builder addIntAnnotation(final byte annotationId, final int value) {
+            if (0 == mPosLastField) {
+                mErrorMask |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
+            } else if (mCurrentAnnotationCount >= MAX_ANNOTATION_COUNT) {
+                mErrorMask |= ERROR_TOO_MANY_ANNOTATIONS;
+            } else {
+                mPos += mBuffer.putByte(mPos, annotationId);
+                mPos += mBuffer.putByte(mPos, TYPE_INT);
+                mPos += mBuffer.putInt(mPos, value);
+                mCurrentAnnotationCount++;
+                writeAnnotationCount();
+            }
+            return this;
+        }
+
+        /**
+         * Builds a StatsEvent object with values entered in this Builder.
+         **/
+        @NonNull
+        public StatsEvent build() {
+            if (0L == mTimestampNs) {
+                mErrorMask |= ERROR_NO_TIMESTAMP;
+            }
+            if (0 == mAtomId) {
+                mErrorMask |= ERROR_NO_ATOM_ID;
+            }
+            if (mBuffer.hasOverflowed()) {
+                mErrorMask |= ERROR_OVERFLOW;
+            }
+            if (mNumElements > MAX_NUM_ELEMENTS) {
+                mErrorMask |= ERROR_TOO_MANY_FIELDS;
             }
 
-            mBuffer[pos] = LIST_TYPE;
-            mBuffer[pos + 1] = 2;
-            pos += LIST_TYPE_OVERHEAD;
-            mBuffer[pos] = INT_TYPE;
-            copyInt(mBuffer, pos + 1, uids[i]);
-            pos += INT_TYPE_SIZE;
-            mBuffer[pos] = STRING_TYPE;
-            copyInt(mBuffer, pos + 1, tagBytes.length);
-            System.arraycopy(tagBytes, 0, mBuffer, pos + STRING_TYPE_OVERHEAD, tagBytes.length);
-            pos += STRING_TYPE_OVERHEAD + tagBytes.length;
+            int size = mPos;
+            mPos = POS_TIMESTAMP_NS;
+            writeLong(mTimestampNs);
+            writeInt(mAtomId);
+            if (0 == mErrorMask) {
+                mBuffer.putByte(POS_NUM_ELEMENTS, (byte) mNumElements);
+            } else {
+                mBuffer.putByte(0, TYPE_ERRORS);
+                mBuffer.putByte(POS_NUM_ELEMENTS, (byte) 3);
+                mPos += mBuffer.putInt(mPos, mErrorMask);
+                size = mPos;
+            }
+
+            return new StatsEvent(mBuffer, size);
         }
-        mPos = pos;
-        mNumElements++;
-        return SUCCESS;
+
+        private void writeTypeId(final byte typeId) {
+            mPosLastField = mPos;
+            mLastType = typeId;
+            mCurrentAnnotationCount = 0;
+            final byte encodedId = (byte) (typeId & 0x0F);
+            mPos += mBuffer.putByte(mPos, encodedId);
+        }
+
+        private void writeAnnotationCount() {
+            // Use first 4 bits for annotation count and last 4 bits for typeId.
+            final byte encodedId = (byte) ((mCurrentAnnotationCount << 4) | (mLastType & 0x0F));
+            mBuffer.putByte(mPosLastField, encodedId);
+        }
+
+        @NonNull
+        private static byte[] stringToBytes(@Nullable final String value) {
+            return (null == value ? "" : value).getBytes(UTF_8);
+        }
     }
 
-    /**
-     * Returns the byte array containing data in the statsd socket format.
-     * @hide
-     **/
-    @NonNull
-    public byte[] getBuffer() {
-        // Encode number of elements in the buffer.
-        mBuffer[POS_NUM_ELEMENTS] = (byte) mNumElements;
-        return mBuffer;
-    }
+    private static final class Buffer {
+        private static Object sLock = new Object();
 
-    /**
-     * Returns number of bytes used by the buffer.
-     * @hide
-     **/
-    public int size() {
-        return mPos;
-    }
+        @GuardedBy("sLock")
+        private static Buffer sPool;
 
-    /**
-     * Getter for atom id.
-     * @hide
-     **/
-    public int getAtomId() {
-        return mAtomId;
-    }
+        private final byte[] mBytes = new byte[MAX_PAYLOAD_SIZE];
+        private boolean mOverflow = false;
 
-    @NonNull
-    private static byte[] stringToBytes(@Nullable final String value) {
-        return (null == value ? "" : value).getBytes(UTF_8);
-    }
+        @NonNull
+        private static Buffer obtain() {
+            final Buffer buffer;
+            synchronized (sLock) {
+                buffer = null == sPool ? new Buffer() : sPool;
+                sPool = null;
+            }
+            buffer.reset();
+            return buffer;
+        }
 
-    // Helper methods for copying primitives
-    private static void copyInt(@NonNull byte[] buff, int pos, int value) {
-        buff[pos] = (byte) (value);
-        buff[pos + 1] = (byte) (value >> 8);
-        buff[pos + 2] = (byte) (value >> 16);
-        buff[pos + 3] = (byte) (value >> 24);
-    }
+        private Buffer() {
+        }
 
-    private static void copyLong(@NonNull byte[] buff, int pos, long value) {
-        buff[pos] = (byte) (value);
-        buff[pos + 1] = (byte) (value >> 8);
-        buff[pos + 2] = (byte) (value >> 16);
-        buff[pos + 3] = (byte) (value >> 24);
-        buff[pos + 4] = (byte) (value >> 32);
-        buff[pos + 5] = (byte) (value >> 40);
-        buff[pos + 6] = (byte) (value >> 48);
-        buff[pos + 7] = (byte) (value >> 56);
+        @NonNull
+        private byte[] getBytes() {
+            return mBytes;
+        }
+
+        private void release() {
+            synchronized (sLock) {
+                if (null == sPool) {
+                    sPool = this;
+                }
+            }
+        }
+
+        private void reset() {
+            mOverflow = false;
+        }
+
+        private boolean hasOverflowed() {
+            return mOverflow;
+        }
+
+        /**
+         * Checks for available space in the byte array.
+         *
+         * @param index starting position in the buffer to start the check.
+         * @param numBytes number of bytes to check from index.
+         * @return true if space is available, false otherwise.
+         **/
+        private boolean hasEnoughSpace(final int index, final int numBytes) {
+            final boolean result = index + numBytes < MAX_PAYLOAD_SIZE;
+            if (!result) {
+                mOverflow = true;
+            }
+            return result;
+        }
+
+        /**
+         * Writes a byte into the buffer.
+         *
+         * @param index position in the buffer where the byte is written.
+         * @param value the byte to write.
+         * @return number of bytes written to buffer from this write operation.
+         **/
+        private int putByte(final int index, final byte value) {
+            if (hasEnoughSpace(index, Byte.BYTES)) {
+                mBytes[index] = (byte) (value);
+                return Byte.BYTES;
+            }
+            return 0;
+        }
+
+        /**
+         * Writes a boolean into the buffer.
+         *
+         * @param index position in the buffer where the boolean is written.
+         * @param value the boolean to write.
+         * @return number of bytes written to buffer from this write operation.
+         **/
+        private int putBoolean(final int index, final boolean value) {
+            return putByte(index, (byte) (value ? 1 : 0));
+        }
+
+        /**
+         * Writes an integer into the buffer.
+         *
+         * @param index position in the buffer where the integer is written.
+         * @param value the integer to write.
+         * @return number of bytes written to buffer from this write operation.
+         **/
+        private int putInt(final int index, final int value) {
+            if (hasEnoughSpace(index, Integer.BYTES)) {
+                // Use little endian byte order.
+                mBytes[index] = (byte) (value);
+                mBytes[index + 1] = (byte) (value >> 8);
+                mBytes[index + 2] = (byte) (value >> 16);
+                mBytes[index + 3] = (byte) (value >> 24);
+                return Integer.BYTES;
+            }
+            return 0;
+        }
+
+        /**
+         * Writes a long into the buffer.
+         *
+         * @param index position in the buffer where the long is written.
+         * @param value the long to write.
+         * @return number of bytes written to buffer from this write operation.
+         **/
+        private int putLong(final int index, final long value) {
+            if (hasEnoughSpace(index, Long.BYTES)) {
+                // Use little endian byte order.
+                mBytes[index] = (byte) (value);
+                mBytes[index + 1] = (byte) (value >> 8);
+                mBytes[index + 2] = (byte) (value >> 16);
+                mBytes[index + 3] = (byte) (value >> 24);
+                mBytes[index + 4] = (byte) (value >> 32);
+                mBytes[index + 5] = (byte) (value >> 40);
+                mBytes[index + 6] = (byte) (value >> 48);
+                mBytes[index + 7] = (byte) (value >> 56);
+                return Long.BYTES;
+            }
+            return 0;
+        }
+
+        /**
+         * Writes a float into the buffer.
+         *
+         * @param index position in the buffer where the float is written.
+         * @param value the float to write.
+         * @return number of bytes written to buffer from this write operation.
+         **/
+        private int putFloat(final int index, final float value) {
+            return putInt(index, Float.floatToIntBits(value));
+        }
+
+        /**
+         * Copies a byte array into the buffer.
+         *
+         * @param index position in the buffer where the byte array is copied.
+         * @param value the byte array to copy.
+         * @return number of bytes written to buffer from this write operation.
+         **/
+        private int putByteArray(final int index, @NonNull final byte[] value) {
+            final int numBytes = value.length;
+            if (hasEnoughSpace(index, numBytes)) {
+                System.arraycopy(value, 0, mBytes, index, numBytes);
+                return numBytes;
+            }
+            return 0;
+        }
     }
 }
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 8fbbcf4..d59ee92 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -145,7 +145,7 @@
         boolean onSingleTapConfirmed(MotionEvent e);
  
         /**
-         * Notified when a double-tap occurs.
+         * Notified when a double-tap occurs. Triggered on the down event of second tap.
          *
          * @param e The down motion event of the first tap of the double-tap.
          * @return true if the event is consumed, else false
@@ -378,7 +378,9 @@
      *
      * @param context the application's context
      * @param listener the listener invoked for all the callbacks, this must
-     * not be null.
+     * not be null. If the listener implements the {@link OnDoubleTapListener} or
+     * {@link OnContextClickListener} then it will also be set as the listener for
+     * these callbacks (for example when using the {@link SimpleOnGestureListener}).
      *
      * @throws NullPointerException if {@code listener} is null.
      */
@@ -393,7 +395,9 @@
      *
      * @param context the application's context
      * @param listener the listener invoked for all the callbacks, this must
-     * not be null.
+     * not be null. If the listener implements the {@link OnDoubleTapListener} or
+     * {@link OnContextClickListener} then it will also be set as the listener for
+     * these callbacks (for example when using the {@link SimpleOnGestureListener}).
      * @param handler the handler to use for running deferred listener events.
      *
      * @throws NullPointerException if {@code listener} is null.
diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java
index db01cea..37b9eb3 100644
--- a/core/java/android/view/HapticFeedbackConstants.java
+++ b/core/java/android/view/HapticFeedbackConstants.java
@@ -115,13 +115,11 @@
     /**
      * A haptic effect to signal the confirmation or successful completion of a user
      * interaction.
-     * @hide
      */
     public static final int CONFIRM = 16;
 
     /**
      * A haptic effect to signal the rejection or failure of a user interaction.
-     * @hide
      */
     public static final int REJECT = 17;
 
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ComponentBinder.java b/core/java/android/view/IWindowContainer.aidl
similarity index 60%
copy from packages/SystemUI/src/com/android/systemui/dagger/ComponentBinder.java
copy to core/java/android/view/IWindowContainer.aidl
index 4e4c06e..878d86b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ComponentBinder.java
+++ b/core/java/android/view/IWindowContainer.aidl
@@ -14,18 +14,19 @@
  * limitations under the License.
  */
 
-package com.android.systemui.dagger;
+package android.view;
 
-import dagger.Binds;
-import dagger.Module;
+import android.view.SurfaceControl;
 
 /**
- * Dagger Module that collects related sub-modules together.
+ * Interface for a window container to communicate with the window manager. This also acts as a
+ * token.
+ * @hide
  */
-@Module(includes = {ActivityBinder.class, ServiceBinder.class, SystemUIBinder.class})
-public abstract class ComponentBinder {
-    /** */
-    @Binds
-    public abstract ContextComponentHelper bindComponentHelper(
-            ContextComponentResolver componentHelper);
+interface IWindowContainer {
+
+    /**
+     * Gets a persistent leash for this container or {@code null}.
+     */
+    SurfaceControl getLeash();
 }
diff --git a/core/java/android/view/InputChannel.java b/core/java/android/view/InputChannel.java
index 831e9ee..5d0d5bd 100644
--- a/core/java/android/view/InputChannel.java
+++ b/core/java/android/view/InputChannel.java
@@ -61,7 +61,6 @@
     private native void nativeWriteToParcel(Parcel parcel);
     private native void nativeDup(InputChannel target);
     private native IBinder nativeGetToken();
-    private native void nativeSetToken(IBinder token);
 
     private native String nativeGetName();
 
@@ -185,8 +184,4 @@
     public IBinder getToken() {
         return nativeGetToken();
     }
-
-    public void setToken(IBinder token) {
-        nativeSetToken(token);
-    }
 }
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 0fb1c33..786dbb0 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import static android.view.InsetsState.INSET_SIDE_BOTTOM;
+import static android.view.InsetsState.INSET_SIDE_FLOATING;
 import static android.view.InsetsState.INSET_SIDE_LEFT;
 import static android.view.InsetsState.INSET_SIDE_RIGHT;
 import static android.view.InsetsState.INSET_SIDE_TOP;
@@ -151,6 +152,8 @@
         updateLeashesForSide(INSET_SIDE_RIGHT, offset.right, mPendingInsets.right, params, state);
         updateLeashesForSide(INSET_SIDE_BOTTOM, offset.bottom, mPendingInsets.bottom, params,
                 state);
+        updateLeashesForSide(INSET_SIDE_FLOATING, 0 /* offset */, 0 /* inset */, params, state);
+
         SyncRtSurfaceTransactionApplier applier = mTransactionApplierSupplier.get();
         applier.scheduleApply(params.toArray(new SurfaceParams[params.size()]));
         mCurrentInsets = mPendingInsets;
@@ -238,7 +241,9 @@
             // If the system is controlling the insets source, the leash can be null.
             if (leash != null) {
                 surfaceParams.add(new SurfaceParams(leash, 1f /* alpha */, mTmpMatrix,
-                        null /* windowCrop */, 0 /* layer */, 0f /* cornerRadius*/, inset != 0));
+                        null /* windowCrop */, 0 /* layer */, 0f /* cornerRadius*/,
+                        side == INSET_SIDE_FLOATING
+                                ? consumer.isVisible() : inset != 0 /* visible */));
             }
         }
     }
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 99502a6..e9de3f0 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -109,6 +109,7 @@
             INSET_SIDE_TOP,
             INSET_SIDE_RIGHT,
             INSET_SIDE_BOTTOM,
+            INSET_SIDE_FLOATING,
             INSET_SIDE_UNKNWON
     })
     public @interface InsetSide {}
@@ -116,7 +117,8 @@
     static final int INSET_SIDE_TOP = 1;
     static final int INSET_SIDE_RIGHT = 2;
     static final int INSET_SIDE_BOTTOM = 3;
-    static final int INSET_SIDE_UNKNWON = 4;
+    static final int INSET_SIDE_FLOATING = 4;
+    static final int INSET_SIDE_UNKNWON = 5;
 
     private final ArrayMap<Integer, InsetsSource> mSources = new ArrayMap<>();
 
@@ -224,10 +226,10 @@
             typeVisibilityMap[index] = source.isVisible();
         }
 
-        if (typeSideMap != null && !Insets.NONE.equals(insets)) {
+        if (typeSideMap != null) {
             @InsetSide int insetSide = getInsetSide(insets);
             if (insetSide != INSET_SIDE_UNKNWON) {
-                typeSideMap.put(source.getType(), getInsetSide(insets));
+                typeSideMap.put(source.getType(), insetSide);
             }
         }
     }
@@ -237,6 +239,9 @@
      * is set in order that this method returns a meaningful result.
      */
     private @InsetSide int getInsetSide(Insets insets) {
+        if (Insets.NONE.equals(insets)) {
+            return INSET_SIDE_FLOATING;
+        }
         if (insets.left != 0) {
             return INSET_SIDE_LEFT;
         }
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 2f0a4eb..59e9ed1 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -712,6 +712,8 @@
         mSurfaceAlpha = 1f;
 
         synchronized (mSurfaceControlLock) {
+            mSurface.release();
+
             if (mRtHandlingPositionUpdates) {
                 mRtReleaseSurfaces = true;
                 return;
@@ -725,7 +727,6 @@
                 mTmpTransaction.remove(mBackgroundControl);
                 mBackgroundControl = null;
             }
-            mSurface.release();
             mTmpTransaction.apply();
         }
     }
@@ -1198,7 +1199,6 @@
                     mRtTransaction.remove(mBackgroundControl);
                     mSurfaceControl = null;
                     mBackgroundControl = null;
-                    mSurface.release();
                 }
                 mRtHandlingPositionUpdates = false;
             }
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index ad59ae5..36daa5c 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -945,6 +945,94 @@
         return null;
     }
 
+    private static class StreamingPictureCallbackHandler implements AutoCloseable,
+            HardwareRenderer.PictureCapturedCallback, Runnable {
+        private final HardwareRenderer mRenderer;
+        private final Callable<OutputStream> mCallback;
+        private final Executor mExecutor;
+        private final ReentrantLock mLock = new ReentrantLock(false);
+        private final ArrayDeque<byte[]> mQueue = new ArrayDeque<>(3);
+        private final ByteArrayOutputStream mByteStream = new ByteArrayOutputStream();
+        private boolean mStopListening;
+        private Thread mRenderThread;
+
+        private StreamingPictureCallbackHandler(HardwareRenderer renderer,
+                Callable<OutputStream> callback, Executor executor) {
+            mRenderer = renderer;
+            mCallback = callback;
+            mExecutor = executor;
+            mRenderer.setPictureCaptureCallback(this);
+        }
+
+        @Override
+        public void close() {
+            mLock.lock();
+            mStopListening = true;
+            mLock.unlock();
+            mRenderer.setPictureCaptureCallback(null);
+        }
+
+        @Override
+        public void onPictureCaptured(Picture picture) {
+            mLock.lock();
+            if (mStopListening) {
+                mLock.unlock();
+                mRenderer.setPictureCaptureCallback(null);
+                return;
+            }
+            if (mRenderThread == null) {
+                mRenderThread = Thread.currentThread();
+            }
+            boolean needsInvoke = true;
+            if (mQueue.size() == 3) {
+                mQueue.removeLast();
+                needsInvoke = false;
+            }
+            picture.writeToStream(mByteStream);
+            mQueue.add(mByteStream.toByteArray());
+            mByteStream.reset();
+            mLock.unlock();
+
+            if (needsInvoke) {
+                mExecutor.execute(this);
+            }
+        }
+
+        @Override
+        public void run() {
+            mLock.lock();
+            final byte[] picture = mQueue.poll();
+            final boolean isStopped = mStopListening;
+            mLock.unlock();
+            if (Thread.currentThread() == mRenderThread) {
+                close();
+                throw new IllegalStateException(
+                        "ViewDebug#startRenderingCommandsCapture must be given an executor that "
+                        + "invokes asynchronously");
+            }
+            if (isStopped) {
+                return;
+            }
+            OutputStream stream = null;
+            try {
+                stream = mCallback.call();
+            } catch (Exception ex) {
+                Log.w("ViewDebug", "Aborting rendering commands capture "
+                        + "because callback threw exception", ex);
+            }
+            if (stream != null) {
+                try {
+                    stream.write(picture);
+                } catch (IOException ex) {
+                    Log.w("ViewDebug", "Aborting rendering commands capture "
+                            + "due to IOException writing to output stream", ex);
+                }
+            } else {
+                close();
+            }
+        }
+    }
+
     /**
      * Begins capturing the entire rendering commands for the view tree referenced by the given
      * view. The view passed may be any View in the tree as long as it is attached. That is,
@@ -990,18 +1078,7 @@
         }
         final HardwareRenderer renderer = attachInfo.mThreadedRenderer;
         if (renderer != null) {
-            return new PictureCallbackHandler(renderer, (picture -> {
-                try {
-                    OutputStream stream = callback.call();
-                    if (stream != null) {
-                        picture.writeToStream(stream);
-                        return true;
-                    }
-                } catch (Exception ex) {
-                    // fall through
-                }
-                return false;
-            }), executor);
+            return new StreamingPictureCallbackHandler(renderer, callback, executor);
         }
         return null;
     }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 20dc234..85bf19f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -439,7 +439,6 @@
     boolean mReportNextDraw;
     boolean mFullRedrawNeeded;
     boolean mNewSurfaceNeeded;
-    boolean mHasHadWindowFocus;
     boolean mLastWasImTarget;
     boolean mForceNextWindowRelayout;
     CountDownLatch mWindowDrawCountDown;
@@ -2123,11 +2122,6 @@
                 endDragResizing();
                 destroyHardwareResources();
             }
-            if (viewVisibility == View.GONE) {
-                // After making a window gone, we will count it as being
-                // shown for the first time the next time it gets focus.
-                mHasHadWindowFocus = false;
-            }
         }
 
         // Non-visible windows can't hold accessibility focus.
@@ -2823,8 +2817,7 @@
                 if (imm != null && imTarget) {
                     imm.onPreWindowFocus(mView, hasWindowFocus);
                     imm.onPostWindowFocus(mView, mView.findFocus(),
-                            mWindowAttributes.softInputMode,
-                            !mHasHadWindowFocus, mWindowAttributes.flags);
+                            mWindowAttributes.softInputMode, mWindowAttributes.flags);
                 }
             }
         }
@@ -3017,8 +3010,7 @@
             if (hasWindowFocus) {
                 if (imm != null && mLastWasImTarget && !isInLocalFocusMode()) {
                     imm.onPostWindowFocus(mView, mView.findFocus(),
-                            mWindowAttributes.softInputMode,
-                            !mHasHadWindowFocus, mWindowAttributes.flags);
+                            mWindowAttributes.softInputMode, mWindowAttributes.flags);
                 }
                 // Clear the forward bit.  We can just do this directly, since
                 // the window manager doesn't care about it.
@@ -3028,7 +3020,6 @@
                         .softInputMode &=
                         ~WindowManager.LayoutParams
                                 .SOFT_INPUT_IS_FORWARD_NAVIGATION;
-                mHasHadWindowFocus = true;
 
                 // Refocusing a window that has a focused view should fire a
                 // focus event for the view since the global focused view changed.
diff --git a/core/java/android/view/WindowContainerTransaction.aidl b/core/java/android/view/WindowContainerTransaction.aidl
new file mode 100644
index 0000000..46ba6c1
--- /dev/null
+++ b/core/java/android/view/WindowContainerTransaction.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.view;
+
+parcelable WindowContainerTransaction;
diff --git a/core/java/android/view/WindowContainerTransaction.java b/core/java/android/view/WindowContainerTransaction.java
new file mode 100644
index 0000000..607a870
--- /dev/null
+++ b/core/java/android/view/WindowContainerTransaction.java
@@ -0,0 +1,173 @@
+/*
+ * 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.view;
+
+import android.app.WindowConfiguration;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+
+import java.util.Map;
+
+/**
+ * Represents a collection of operations on some WindowContainers that should be applied all at
+ * once.
+ *
+ * @hide
+ */
+public class WindowContainerTransaction implements Parcelable {
+    private final ArrayMap<IBinder, Change> mChanges = new ArrayMap<>();
+
+    public WindowContainerTransaction() {}
+
+    protected WindowContainerTransaction(Parcel in) {
+        in.readMap(mChanges, null /* loader */);
+    }
+
+    private Change getOrCreateChange(IBinder token) {
+        Change out = mChanges.get(token);
+        if (out == null) {
+            out = new Change();
+            mChanges.put(token, out);
+        }
+        return out;
+    }
+
+    /**
+     * Resize a container.
+     */
+    public WindowContainerTransaction setBounds(IWindowContainer container, Rect bounds) {
+        Change chg = getOrCreateChange(container.asBinder());
+        chg.mConfiguration.windowConfiguration.setBounds(bounds);
+        chg.mConfigSetMask |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
+        chg.mWindowSetMask |= WindowConfiguration.WINDOW_CONFIG_BOUNDS;
+        return this;
+    }
+
+    public Map<IBinder, Change> getChanges() {
+        return mChanges;
+    }
+
+    @Override
+    public String toString() {
+        return "WindowContainerTransaction { changes = " + mChanges + " }";
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeMap(mChanges);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Creator<WindowContainerTransaction> CREATOR =
+            new Creator<WindowContainerTransaction>() {
+                @Override
+                public WindowContainerTransaction createFromParcel(Parcel in) {
+                    return new WindowContainerTransaction(in);
+                }
+
+                @Override
+                public WindowContainerTransaction[] newArray(int size) {
+                    return new WindowContainerTransaction[size];
+                }
+            };
+
+    /**
+     * Holds changes on a single WindowContainer including Configuration changes.
+     *
+     * @hide
+     */
+    public static class Change implements Parcelable {
+        private final Configuration mConfiguration = new Configuration();
+        private @ActivityInfo.Config int mConfigSetMask = 0;
+        private @WindowConfiguration.WindowConfig int mWindowSetMask = 0;
+
+        public Change() {}
+
+        protected Change(Parcel in) {
+            mConfiguration.readFromParcel(in);
+            mConfigSetMask = in.readInt();
+            mWindowSetMask = in.readInt();
+        }
+
+        public Configuration getConfiguration() {
+            return mConfiguration;
+        }
+
+        @ActivityInfo.Config
+        public int getConfigSetMask() {
+            return mConfigSetMask;
+        }
+
+        @WindowConfiguration.WindowConfig
+        public int getWindowSetMask() {
+            return mWindowSetMask;
+        }
+
+        @Override
+        public String toString() {
+            final boolean changesBounds =
+                    (mConfigSetMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
+                            && ((mWindowSetMask & WindowConfiguration.WINDOW_CONFIG_BOUNDS)
+                                    != 0);
+            final boolean changesSss =
+                    (mConfigSetMask & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0;
+            StringBuilder sb = new StringBuilder();
+            sb.append('{');
+            if (changesBounds) {
+                sb.append("bounds:" + mConfiguration.windowConfiguration.getBounds() + ",");
+            }
+            if (changesSss) {
+                sb.append("ssw:" + mConfiguration.smallestScreenWidthDp + ",");
+            }
+            sb.append("}");
+            return sb.toString();
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            mConfiguration.writeToParcel(dest, flags);
+            dest.writeInt(mConfigSetMask);
+            dest.writeInt(mWindowSetMask);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Creator<Change> CREATOR = new Creator<Change>() {
+            @Override
+            public Change createFromParcel(Parcel in) {
+                return new Change(in);
+            }
+
+            @Override
+            public Change[] newArray(int size) {
+                return new Change[size];
+            }
+        };
+    }
+}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 6420d71..e81db16 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -92,7 +92,10 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -358,7 +361,7 @@
     boolean mActive = false;
 
     /**
-     * {@code true} if next {@link #onPostWindowFocus(View, View, int, boolean, int)} needs to
+     * {@code true} if next {@link #onPostWindowFocus(View, View, int, int)} needs to
      * restart input.
      */
     boolean mRestartOnNextWindowFocus = true;
@@ -422,6 +425,13 @@
     int mCursorCandEnd;
 
     /**
+     * Initial startInput with {@link StartInputReason.WINDOW_FOCUS_GAIN} is executed
+     * in a background thread. Later, if there is an actual startInput it will wait on
+     * main thread till the background thread completes.
+     */
+    private CompletableFuture<Void> mWindowFocusGainFuture;
+
+    /**
      * The instance that has previously been sent to the input method.
      */
     private CursorAnchorInfo mCursorAnchorInfo = null;
@@ -1598,6 +1608,18 @@
     boolean startInputInner(@StartInputReason int startInputReason,
             @Nullable IBinder windowGainingFocus, @StartInputFlags int startInputFlags,
             @SoftInputModeFlags int softInputMode, int windowFlags) {
+        if (startInputReason != StartInputReason.WINDOW_FOCUS_GAIN
+                && mWindowFocusGainFuture != null) {
+            try {
+                mWindowFocusGainFuture.get();
+            } catch (ExecutionException | InterruptedException e) {
+                // do nothing
+            } catch (CancellationException e) {
+                // window no longer has focus.
+                return true;
+            }
+        }
+
         final View view;
         synchronized (mH) {
             view = mServedView;
@@ -1925,13 +1947,12 @@
      * @hide
      */
     public void onPostWindowFocus(View rootView, View focusedView,
-            @SoftInputModeFlags int softInputMode, boolean first, int windowFlags) {
+            @SoftInputModeFlags int softInputMode, int windowFlags) {
         boolean forceNewFocus = false;
         synchronized (mH) {
             if (DEBUG) Log.v(TAG, "onWindowFocus: " + focusedView
                     + " softInputMode=" + InputMethodDebug.softInputModeToString(softInputMode)
-                    + " first=" + first + " flags=#"
-                    + Integer.toHexString(windowFlags));
+                    + " flags=#" + Integer.toHexString(windowFlags));
             if (mRestartOnNextWindowFocus) {
                 if (DEBUG) Log.v(TAG, "Restarting due to mRestartOnNextWindowFocus");
                 mRestartOnNextWindowFocus = false;
@@ -1947,35 +1968,39 @@
                 startInputFlags |= StartInputFlags.IS_TEXT_EDITOR;
             }
         }
-        if (first) {
-            startInputFlags |= StartInputFlags.FIRST_WINDOW_FOCUS_GAIN;
-        }
 
-        if (checkFocusNoStartInput(forceNewFocus)) {
-            // We need to restart input on the current focus view.  This
-            // should be done in conjunction with telling the system service
-            // about the window gaining focus, to help make the transition
-            // smooth.
-            if (startInputInner(StartInputReason.WINDOW_FOCUS_GAIN, rootView.getWindowToken(),
-                    startInputFlags, softInputMode, windowFlags)) {
-                return;
-            }
+        final boolean forceNewFocus1 = forceNewFocus;
+        final int startInputFlags1 = startInputFlags;
+        if (mWindowFocusGainFuture != null) {
+            mWindowFocusGainFuture.cancel(false/* mayInterruptIfRunning */);
         }
+        mWindowFocusGainFuture = CompletableFuture.runAsync(() -> {
+            if (checkFocusNoStartInput(forceNewFocus1)) {
+                // We need to restart input on the current focus view.  This
+                // should be done in conjunction with telling the system service
+                // about the window gaining focus, to help make the transition
+                // smooth.
+                if (startInputInner(StartInputReason.WINDOW_FOCUS_GAIN, rootView.getWindowToken(),
+                        startInputFlags1, softInputMode, windowFlags)) {
+                    return;
+                }
+            }
 
-        // For some reason we didn't do a startInput + windowFocusGain, so
-        // we'll just do a window focus gain and call it a day.
-        synchronized (mH) {
-            try {
-                if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput");
-                mService.startInputOrWindowGainedFocus(
-                        StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient,
-                        rootView.getWindowToken(), startInputFlags, softInputMode, windowFlags,
-                        null, null, 0 /* missingMethodFlags */,
-                        rootView.getContext().getApplicationInfo().targetSdkVersion);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
+            // For some reason we didn't do a startInput + windowFocusGain, so
+            // we'll just do a window focus gain and call it a day.
+            synchronized (mH) {
+                try {
+                    if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput");
+                    mService.startInputOrWindowGainedFocus(
+                            StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient,
+                            rootView.getWindowToken(), startInputFlags1, softInputMode, windowFlags,
+                            null, null, 0 /* missingMethodFlags */,
+                            rootView.getContext().getApplicationInfo().targetSdkVersion);
+                } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
+                }
             }
-        }
+        });
     }
 
     /** @hide */
@@ -1990,6 +2015,10 @@
                 // If the mCurRootView is losing window focus, release the strong reference to it
                 // so as not to prevent it from being garbage-collected.
                 mCurRootView = null;
+                if (mWindowFocusGainFuture != null) {
+                    mWindowFocusGainFuture.cancel(false /* mayInterruptIfRunning */);
+                    mWindowFocusGainFuture = null;
+                }
             } else {
                 if (DEBUG) {
                     Log.v(TAG, "Ignoring onPreWindowFocus()."
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 23d1237..3824c22 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -22,7 +22,10 @@
 
 /**
  * Manages the cookies used by an application's {@link WebView} instances.
- * Cookies are manipulated according to RFC2109.
+ * <p>
+ * CookieManager represents cookies as strings in the same format as the
+ * HTTP {@code Cookie} and {@code Set-Cookie} header fields (defined in
+ * <a href="https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03">RFC6265bis</a>).
  */
 public abstract class CookieManager {
     /**
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 4db6308..f8522ed 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -71,11 +71,24 @@
     }
 
     /**
-     * Notify the host application that the current page has entered full
-     * screen mode. The host application must show the custom View which
-     * contains the web contents &mdash; video or other HTML content &mdash;
-     * in full screen mode. Also see "Full screen support" documentation on
-     * {@link WebView}.
+     * Notify the host application that the current page has entered full screen mode. After this
+     * call, web content will no longer be rendered in the WebView, but will instead be rendered
+     * in {@code view}. The host application should add this View to a Window which is configured
+     * with {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN} flag in order to
+     * actually display this web content full screen.
+     *
+     * <p>The application may explicitly exit fullscreen mode by invoking {@code callback} (ex. when
+     * the user presses the back button). However, this is generally not necessary as the web page
+     * will often show its own UI to close out of fullscreen. Regardless of how the WebView exits
+     * fullscreen mode, WebView will invoke {@link #onHideCustomView()}, signaling for the
+     * application to remove the custom View.
+     *
+     * <p>If this method is not overridden, WebView will report to the web page it does not support
+     * fullscreen mode and will not honor the web page's request to run in fullscreen mode.
+     *
+     * <p class="note"><b>Note:</b> if overriding this method, the application must also override
+     * {@link #onHideCustomView()}.
+     *
      * @param view is the View object to be shown.
      * @param callback invoke this callback to request the page to exit
      * full screen mode.
@@ -98,10 +111,13 @@
             CustomViewCallback callback) {};
 
     /**
-     * Notify the host application that the current page has exited full
-     * screen mode. The host application must hide the custom View, ie. the
-     * View passed to {@link #onShowCustomView} when the content entered fullscreen.
-     * Also see "Full screen support" documentation on {@link WebView}.
+     * Notify the host application that the current page has exited full screen mode. The host
+     * application must hide the custom View (the View which was previously passed to {@link
+     * #onShowCustomView(View, CustomViewCallback) onShowCustomView()}). After this call, web
+     * content will render in the original WebView again.
+     *
+     * <p class="note"><b>Note:</b> if overriding this method, the application must also override
+     * {@link #onShowCustomView(View, CustomViewCallback) onShowCustomView()}.
      */
     public void onHideCustomView() {}
 
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 57ce28e..27402a4 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1189,6 +1189,9 @@
     }
 
     public boolean performLongClick(boolean handled) {
+        if (TextView.DEBUG_CURSOR) {
+            logCursor("performLongClick", "handled=%s", handled);
+        }
         // Long press in empty space moves cursor and starts the insertion action mode.
         if (!handled && !isPositionOnText(mLastDownPositionX, mLastDownPositionY)
                 && mInsertionControllerEnabled) {
@@ -1252,6 +1255,10 @@
     }
 
     void onFocusChanged(boolean focused, int direction) {
+        if (TextView.DEBUG_CURSOR) {
+            logCursor("onFocusChanged", "focused=%s", focused);
+        }
+
         mShowCursor = SystemClock.uptimeMillis();
         ensureEndedBatchEdit();
 
@@ -1450,12 +1457,22 @@
                 } else {
                     mTapState = TAP_STATE_TRIPLE_CLICK;
                 }
+                if (TextView.DEBUG_CURSOR) {
+                    logCursor("updateTapState", "ACTION_DOWN: %s tap detected",
+                            (mTapState == TAP_STATE_DOUBLE_TAP ? "double" : "triple"));
+                }
             } else {
                 mTapState = TAP_STATE_FIRST_TAP;
+                if (TextView.DEBUG_CURSOR) {
+                    logCursor("updateTapState", "ACTION_DOWN: first tap detected");
+                }
             }
         }
         if (action == MotionEvent.ACTION_UP) {
             mLastTouchUpTime = SystemClock.uptimeMillis();
+            if (TextView.DEBUG_CURSOR) {
+                logCursor("updateTapState", "ACTION_UP");
+            }
         }
     }
 
@@ -2354,6 +2371,9 @@
     }
 
     void onTouchUpEvent(MotionEvent event) {
+        if (TextView.DEBUG_CURSOR) {
+            logCursor("onTouchUpEvent", null);
+        }
         if (getSelectionActionModeHelper().resetSelection(
                 getTextView().getOffsetForPosition(event.getX(), event.getY()))) {
             return;
@@ -2481,6 +2501,9 @@
         loadCursorDrawable();
         final int left = clampHorizontalPosition(mDrawableForCursor, horizontal);
         final int width = mDrawableForCursor.getIntrinsicWidth();
+        if (TextView.DEBUG_CURSOR) {
+            logCursor("updateCursorPosition", "left=%s, top=%s", left, (top - mTempRect.top));
+        }
         mDrawableForCursor.setBounds(left, top - mTempRect.top, left + width,
                 bottom + mTempRect.bottom);
     }
@@ -4621,6 +4644,11 @@
         }
 
         public void show() {
+            if (TextView.DEBUG_CURSOR) {
+                logCursor(getClass().getSimpleName() + ": HandleView: show()", "offset=%s",
+                        getCurrentCursorOffset());
+            }
+
             if (isShowing()) return;
 
             getPositionListener().addSubscriber(this, true /* local position may change */);
@@ -4637,6 +4665,11 @@
         }
 
         public void hide() {
+            if (TextView.DEBUG_CURSOR) {
+                logCursor(getClass().getSimpleName() + ": HandleView: hide()", "offset=%s",
+                        getCurrentCursorOffset());
+            }
+
             dismiss();
 
             getPositionListener().removeSubscriber(this);
@@ -5033,6 +5066,11 @@
 
         @Override
         public boolean onTouchEvent(MotionEvent ev) {
+            if (TextView.DEBUG_CURSOR) {
+                logCursor(this.getClass().getSimpleName() + ": HandleView: onTouchEvent",
+                        MotionEvent.actionToString(ev.getActionMasked()));
+            }
+
             updateFloatingToolbarVisibility(ev);
 
             switch (ev.getActionMasked()) {
@@ -5951,6 +5989,10 @@
                                         distanceSquared < doubleTapSlop * doubleTapSlop;
 
                                 if (stayedInArea && (isMouse || isPositionOnText(eventX, eventY))) {
+                                    if (TextView.DEBUG_CURSOR) {
+                                        logCursor("SelectionModifierCursorController: onTouchEvent",
+                                                "ACTION_DOWN: select and start drag");
+                                    }
                                     if (mTapState == TAP_STATE_DOUBLE_TAP) {
                                         selectCurrentWordAndStartDrag();
                                     } else if (mTapState == TAP_STATE_TRIPLE_CLICK) {
@@ -6028,6 +6070,9 @@
                     break;
 
                 case MotionEvent.ACTION_UP:
+                    if (TextView.DEBUG_CURSOR) {
+                        logCursor("SelectionModifierCursorController: onTouchEvent", "ACTION_UP");
+                    }
                     if (!isDragAcceleratorActive()) {
                         break;
                     }
@@ -7119,4 +7164,12 @@
             return resolveInfo.loadLabel(mPackageManager);
         }
     }
+
+    private static void logCursor(String location, @Nullable String msgFormat, Object ... msgArgs) {
+        if (msgFormat == null) {
+            Log.d(TAG, location);
+        } else {
+            Log.d(TAG, location + ": " + String.format(msgFormat, msgArgs));
+        }
+    }
 }
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 2e95743..d58d858 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -163,7 +163,6 @@
 public class ProgressBar extends View {
 
     private static final int MAX_LEVEL = 10000;
-    private static final int TIMEOUT_SEND_ACCESSIBILITY_EVENT = 200;
 
     /** Interpolator used for smooth progress animations. */
     private static final DecelerateInterpolator PROGRESS_ANIM_INTERPOLATOR =
@@ -244,8 +243,6 @@
 
     private final ArrayList<RefreshData> mRefreshData = new ArrayList<RefreshData>();
 
-    private AccessibilityEventSender mAccessibilityEventSender;
-
     /**
      * Create a new progress bar with range 0...100 and initial progress of 0.
      * @param context the application environment
@@ -1556,7 +1553,7 @@
 
     void onProgressRefresh(float scale, boolean fromUser, int progress) {
         if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-            scheduleAccessibilityEventSender();
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
         }
     }
 
@@ -2250,9 +2247,6 @@
             removeCallbacks(mRefreshProgressRunnable);
             mRefreshIsPosted = false;
         }
-        if (mAccessibilityEventSender != null) {
-            removeCallbacks(mAccessibilityEventSender);
-        }
         // This should come after stopAnimation(), otherwise an invalidate message remains in the
         // queue, which can prevent the entire view hierarchy from being GC'ed during a rotation
         super.onDetachedFromWindow();
@@ -2285,22 +2279,6 @@
         }
     }
 
-    /**
-     * Schedule a command for sending an accessibility event.
-     * </br>
-     * Note: A command is used to ensure that accessibility events
-     *       are sent at most one in a given time frame to save
-     *       system resources while the progress changes quickly.
-     */
-    private void scheduleAccessibilityEventSender() {
-        if (mAccessibilityEventSender == null) {
-            mAccessibilityEventSender = new AccessibilityEventSender();
-        } else {
-            removeCallbacks(mAccessibilityEventSender);
-        }
-        postDelayed(mAccessibilityEventSender, TIMEOUT_SEND_ACCESSIBILITY_EVENT);
-    }
-
     /** @hide */
     @Override
     protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) {
@@ -2324,15 +2302,6 @@
         return isIndeterminate() && getWindowVisibility() == VISIBLE && isShown();
     }
 
-    /**
-     * Command for sending an accessibility event.
-     */
-    private class AccessibilityEventSender implements Runnable {
-        public void run() {
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
-        }
-    }
-
     private static class ProgressTintInfo {
         ColorStateList mIndeterminateTintList;
         BlendMode mIndeterminateBlendMode;
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index 562cc4f..217693e 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -28,6 +28,7 @@
 import android.graphics.Rect;
 import android.graphics.Typeface;
 import android.icu.text.DisplayContext;
+import android.icu.text.RelativeDateTimeFormatter;
 import android.icu.text.SimpleDateFormat;
 import android.icu.util.Calendar;
 import android.os.Bundle;
@@ -1095,6 +1096,14 @@
 
             node.setText(getDayText(virtualViewId));
             node.setContentDescription(getDayDescription(virtualViewId));
+            if (virtualViewId == mToday) {
+                RelativeDateTimeFormatter fmt = RelativeDateTimeFormatter.getInstance();
+                node.setStateDescription(fmt.format(RelativeDateTimeFormatter.Direction.THIS,
+                        RelativeDateTimeFormatter.AbsoluteUnit.DAY));
+            }
+            if (virtualViewId == mActivatedDay) {
+                node.setSelected(true);
+            }
             node.setBoundsInParent(mTempRect);
 
             final boolean isDayEnabled = isDayEnabled(virtualViewId);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 31f5055..90e8ef2 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -345,6 +345,8 @@
 public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {
     static final String LOG_TAG = "TextView";
     static final boolean DEBUG_EXTRACT = false;
+    static final boolean DEBUG_CURSOR = false;
+
     private static final float[] TEMP_POSITION = new float[2];
 
     // Enum for the "typeface" XML parameter.
@@ -10857,6 +10859,10 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
+        if (DEBUG_CURSOR) {
+            logCursor("onTouchEvent", MotionEvent.actionToString(event.getActionMasked()));
+        }
+
         final int action = event.getActionMasked();
         if (mEditor != null) {
             mEditor.onTouchEvent(event);
@@ -10868,6 +10874,9 @@
         }
 
         final boolean superResult = super.onTouchEvent(event);
+        if (DEBUG_CURSOR) {
+            logCursor("onTouchEvent", "superResult=%s", superResult);
+        }
 
         /*
          * Don't handle the release after a long press, because it will move the selection away from
@@ -10876,7 +10885,9 @@
          */
         if (mEditor != null && mEditor.mDiscardNextActionUp && action == MotionEvent.ACTION_UP) {
             mEditor.mDiscardNextActionUp = false;
-
+            if (DEBUG_CURSOR) {
+                logCursor("onTouchEvent", "release after long press detected");
+            }
             if (mEditor.mIsInsertionActionModeStartPending) {
                 mEditor.startInsertionActionMode();
                 mEditor.mIsInsertionActionModeStartPending = false;
@@ -12254,6 +12265,10 @@
 
     @Override
     public boolean performLongClick() {
+        if (DEBUG_CURSOR) {
+            logCursor("performLongClick", null);
+        }
+
         boolean handled = false;
         boolean performedHapticFeedback = false;
 
@@ -13481,4 +13496,12 @@
             TextView.this.spanChange(buf, what, s, -1, e, -1);
         }
     }
+
+    private static void logCursor(String location, @Nullable String msgFormat, Object ... msgArgs) {
+        if (msgFormat == null) {
+            Log.d(LOG_TAG, location);
+        } else {
+            Log.d(LOG_TAG, location + ": " + String.format(msgFormat, msgArgs));
+        }
+    }
 }
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 00c1e29..b1752a4 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -45,8 +45,6 @@
 import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.LabeledIntent;
-import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
@@ -61,9 +59,7 @@
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.drawable.AnimatedVectorDrawable;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
 import android.metrics.LogMaker;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -85,7 +81,6 @@
 import android.service.chooser.ChooserTargetService;
 import android.service.chooser.IChooserTargetResult;
 import android.service.chooser.IChooserTargetService;
-import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.HashedStringCache;
@@ -110,6 +105,14 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.ResolverListAdapter.ActivityInfoPresentationGetter;
+import com.android.internal.app.ResolverListAdapter.ViewHolder;
+import com.android.internal.app.chooser.ChooserTargetInfo;
+import com.android.internal.app.chooser.DisplayResolveInfo;
+import com.android.internal.app.chooser.NotSelectableTargetInfo;
+import com.android.internal.app.chooser.SelectableTargetInfo;
+import com.android.internal.app.chooser.SelectableTargetInfo.SelectableTargetInfoCommunicator;
+import com.android.internal.app.chooser.TargetInfo;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.logging.MetricsLogger;
@@ -124,7 +127,6 @@
 import java.lang.annotation.RetentionPolicy;
 import java.text.Collator;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -138,7 +140,9 @@
  * for example, those generated by @see android.content.Intent#createChooser(Intent, CharSequence).
  *
  */
-public class ChooserActivity extends ResolverActivity {
+public class ChooserActivity extends ResolverActivity implements
+        ChooserListAdapter.ChooserListCommunicator,
+        SelectableTargetInfoCommunicator {
     private static final String TAG = "ChooserActivity";
 
 
@@ -154,12 +158,6 @@
 
     private static final boolean DEBUG = false;
 
-    /**
-     * If {@link #USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS} and this is set to true,
-     * {@link AppPredictionManager} will be queried for direct share targets.
-     */
-    // TODO(b/123089490): Replace with system flag
-    private static final boolean USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS = true;
     private static final boolean USE_PREDICTION_MANAGER_FOR_SHARE_ACTIVITIES = true;
     // TODO(b/123088566) Share these in a better way.
     private static final String APP_PREDICTION_SHARE_UI_SURFACE = "share";
@@ -167,24 +165,21 @@
     private static final int APP_PREDICTION_SHARE_TARGET_QUERY_PACKAGE_LIMIT = 20;
     public static final String APP_PREDICTION_INTENT_FILTER_KEY = "intent_filter";
 
+    @VisibleForTesting
+    public static final int LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS = 250;
+
     private boolean mIsAppPredictorComponentAvailable;
     private AppPredictor mAppPredictor;
     private AppPredictor.Callback mAppPredictorCallback;
     private Map<ChooserTarget, AppTarget> mDirectShareAppTargetCache;
 
-    /**
-     * If set to true, use ShortcutManager to retrieve the matching direct share targets, instead of
-     * binding to every ChooserTargetService implementation.
-     */
-    // TODO(b/121287573): Replace with a system flag (setprop?)
-    private static final boolean USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS = true;
-    private static final boolean USE_CHOOSER_TARGET_SERVICE_FOR_DIRECT_TARGETS = true;
-
     public static final int TARGET_TYPE_DEFAULT = 0;
     public static final int TARGET_TYPE_CHOOSER_TARGET = 1;
     public static final int TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER = 2;
     public static final int TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE = 3;
 
+    private static final boolean USE_CHOOSER_TARGET_SERVICE_FOR_DIRECT_TARGETS = true;
+
     @IntDef(flag = false, prefix = { "TARGET_TYPE_" }, value = {
             TARGET_TYPE_DEFAULT,
             TARGET_TYPE_CHOOSER_TARGET,
@@ -233,10 +228,6 @@
 
     private int mCurrAvailableWidth = 0;
 
-    /** {@link ChooserActivity#getBaseScore} */
-    public static final float CALLER_TARGET_SCORE_BOOST = 900.f;
-    /** {@link ChooserActivity#getBaseScore} */
-    public static final float SHORTCUT_TARGET_SCORE_BOOST = 90.f;
     private static final String TARGET_DETAILS_FRAGMENT_TAG = "targetDetailsFragment";
     // TODO: Update to handle landscape instead of using static value
     private static final int MAX_RANKED_TARGETS = 4;
@@ -246,14 +237,9 @@
 
     private static final int MAX_LOG_RANK_POSITION = 12;
 
-    @VisibleForTesting
-    public static final int LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS = 250;
-
     private static final int MAX_EXTRA_INITIAL_INTENTS = 2;
     private static final int MAX_EXTRA_CHOOSER_TARGETS = 2;
 
-    private boolean mListViewDataChanged = false;
-
     @Retention(SOURCE)
     @IntDef({CONTENT_PREVIEW_FILE, CONTENT_PREVIEW_IMAGE, CONTENT_PREVIEW_TEXT})
     private @interface ContentPreviewType {
@@ -266,9 +252,6 @@
     private static final int CONTENT_PREVIEW_TEXT = 3;
     protected MetricsLogger mMetricsLogger;
 
-    // Sorted list of DisplayResolveInfos for the alphabetical app section.
-    private List<ResolverActivity.DisplayResolveInfo> mSortedList = new ArrayList<>();
-
     private ContentPreviewCoordinator mPreviewCoord;
 
     private class ContentPreviewCoordinator {
@@ -645,8 +628,7 @@
                 if (isFinishing() || isDestroyed()) {
                     return;
                 }
-                // May be null if there are no apps to perform share/open action.
-                if (mChooserListAdapter == null) {
+                if (mChooserListAdapter.getCount() == 0) {
                     return;
                 }
                 if (resultList.isEmpty()) {
@@ -775,7 +757,7 @@
             @Override
             public void onSomePackagesChanged() {
                 mAdapter.handlePackagesChanged();
-                bindProfileView();
+                updateProfileViewButton();
             }
         };
     }
@@ -1191,7 +1173,7 @@
         }
     }
 
-    @Override
+    @Override // ResolverListCommunicator
     public Intent getReplacementIntent(ActivityInfo aInfo, Intent defIntent) {
         Intent result = defIntent;
         if (mReplacementExtras != null) {
@@ -1231,9 +1213,8 @@
     }
 
     @Override
-    public void onPrepareAdapterView(AbsListView adapterView, ResolveListAdapter adapter) {
+    public void onPrepareAdapterView(AbsListView adapterView, ResolverListAdapter adapter) {
         final ListView listView = adapterView instanceof ListView ? (ListView) adapterView : null;
-        mChooserListAdapter = (ChooserListAdapter) adapter;
         if (mCallerChooserTargets != null && mCallerChooserTargets.length > 0) {
             mChooserListAdapter.addServiceResults(null, Lists.newArrayList(mCallerChooserTargets),
                     TARGET_TYPE_DEFAULT);
@@ -1245,11 +1226,17 @@
     }
 
     @Override
+    protected boolean rebuildList() {
+        mChooserListAdapter = (ChooserListAdapter) mAdapter;
+        return rebuildListInternal();
+    }
+
+    @Override
     public int getLayoutResource() {
         return R.layout.chooser_grid;
     }
 
-    @Override
+    @Override // ResolverListCommunicator
     public boolean shouldGetActivityMetadata() {
         return true;
     }
@@ -1328,7 +1315,7 @@
         final long selectionCost = System.currentTimeMillis() - mChooserShownTime;
         super.startSelected(which, always, filtered);
 
-        if (mChooserListAdapter != null) {
+        if (mChooserListAdapter.getCount() > 0) {
             // Log the index of which type of target the user picked.
             // Lower values mean the ranking was better.
             int cat = 0;
@@ -1342,7 +1329,7 @@
                     // Log the package name + target name to answer the question if most users
                     // share to mostly the same person or to a bunch of different people.
                     ChooserTarget target =
-                            mChooserListAdapter.mServiceTargets.get(value).getChooserTarget();
+                            mChooserListAdapter.getChooserTargetForValue(value);
                     directTargetHashed = HashedStringCache.getInstance().hashString(
                             this,
                             TAG,
@@ -1428,7 +1415,7 @@
                 continue;
             }
             final ActivityInfo ai = dri.getResolveInfo().activityInfo;
-            if (USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS
+            if (ChooserFlags.USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS
                     && sm.hasShareTargets(ai.packageName)) {
                 // Share targets will be queried from ShortcutManager
                 continue;
@@ -1817,8 +1804,8 @@
      */
     @Nullable
     private AppPredictor getAppPredictorForDirectShareIfEnabled() {
-        return USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS && !ActivityManager.isLowRamDeviceStatic()
-                ? getAppPredictor() : null;
+        return ChooserFlags.USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS
+                && !ActivityManager.isLowRamDeviceStatic() ? getAppPredictor() : null;
     }
 
     /**
@@ -1900,24 +1887,18 @@
         }
     }
 
-    private void updateAlphabeticalList() {
-        mSortedList.clear();
-        mSortedList.addAll(getDisplayList());
-        Collections.sort(mSortedList, new AzInfoComparator(ChooserActivity.this));
-    }
-
     /**
      * Sort intents alphabetically based on display label.
      */
-    class AzInfoComparator implements Comparator<ResolverActivity.DisplayResolveInfo> {
+    static class AzInfoComparator implements Comparator<DisplayResolveInfo> {
         Collator mCollator;
         AzInfoComparator(Context context) {
             mCollator = Collator.getInstance(context.getResources().getConfiguration().locale);
         }
 
         @Override
-        public int compare(ResolverActivity.DisplayResolveInfo lhsp,
-                ResolverActivity.DisplayResolveInfo rhsp) {
+        public int compare(
+                DisplayResolveInfo lhsp, DisplayResolveInfo rhsp) {
             return mCollator.compare(lhsp.getDisplayLabel(), rhsp.getDisplayLabel());
         }
     }
@@ -1955,12 +1936,12 @@
     }
 
     @Override
-    public ResolveListAdapter createAdapter(Context context, List<Intent> payloadIntents,
-            Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid,
-            boolean filterLastUsed) {
-        final ChooserListAdapter adapter = new ChooserListAdapter(context, payloadIntents,
-                initialIntents, rList, launchedFromUid, filterLastUsed, createListController());
-        return adapter;
+    public ResolverListAdapter createAdapter(Context context, List<Intent> payloadIntents,
+            Intent[] initialIntents, List<ResolveInfo> rList,
+            boolean filterLastUsed, boolean useLayoutForBrowsables) {
+        return new ChooserListAdapter(context, payloadIntents,
+                initialIntents, rList, filterLastUsed, createListController(),
+                useLayoutForBrowsables, this, this);
     }
 
     @VisibleForTesting
@@ -1999,347 +1980,21 @@
         return null;
     }
 
-    interface ChooserTargetInfo extends TargetInfo {
-        float getModifiedScore();
-
-        ChooserTarget getChooserTarget();
-
-        /**
-          * Do not label as 'equals', since this doesn't quite work
-          * as intended with java 8.
-          */
-        default boolean isSimilar(ChooserTargetInfo other) {
-            if (other == null) return false;
-
-            ChooserTarget ct1 = getChooserTarget();
-            ChooserTarget ct2 = other.getChooserTarget();
-
-            // If either is null, there is not enough info to make an informed decision
-            // about equality, so just exit
-            if (ct1 == null || ct2 == null) return false;
-
-            if (ct1.getComponentName().equals(ct2.getComponentName())
-                    && TextUtils.equals(getDisplayLabel(), other.getDisplayLabel())
-                    && TextUtils.equals(getExtendedInfo(), other.getExtendedInfo())) {
-                return true;
-            }
-
-            return false;
-        }
-    }
-
-    /**
-      * Distinguish between targets that selectable by the user, vs those that are
-      * placeholders for the system while information is loading in an async manner.
-      */
-    abstract class NotSelectableTargetInfo implements ChooserTargetInfo {
-
-        public Intent getResolvedIntent() {
-            return null;
-        }
-
-        public ComponentName getResolvedComponentName() {
-            return null;
-        }
-
-        public boolean start(Activity activity, Bundle options) {
-            return false;
-        }
-
-        public boolean startAsCaller(ResolverActivity activity, Bundle options, int userId) {
-            return false;
-        }
-
-        public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
-            return false;
-        }
-
-        public ResolveInfo getResolveInfo() {
-            return null;
-        }
-
-        public CharSequence getDisplayLabel() {
-            return null;
-        }
-
-        public CharSequence getExtendedInfo() {
-            return null;
-        }
-
-        public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
-            return null;
-        }
-
-        public List<Intent> getAllSourceIntents() {
-            return null;
-        }
-
-        public float getModifiedScore() {
-            return -0.1f;
-        }
-
-        public ChooserTarget getChooserTarget() {
-            return null;
-        }
-
-        public boolean isSuspended() {
-            return false;
-        }
-    }
-
-    final class PlaceHolderTargetInfo extends NotSelectableTargetInfo {
-        public Drawable getDisplayIcon() {
+    static final class PlaceHolderTargetInfo extends NotSelectableTargetInfo {
+        public Drawable getDisplayIcon(Context context) {
             AnimatedVectorDrawable avd = (AnimatedVectorDrawable)
-                    getDrawable(R.drawable.chooser_direct_share_icon_placeholder);
+                    context.getDrawable(R.drawable.chooser_direct_share_icon_placeholder);
             avd.start(); // Start animation after generation
             return avd;
         }
     }
 
-
-    final class EmptyTargetInfo extends NotSelectableTargetInfo {
-        public Drawable getDisplayIcon() {
+    static final class EmptyTargetInfo extends NotSelectableTargetInfo {
+        public Drawable getDisplayIcon(Context context) {
             return null;
         }
     }
 
-    final class SelectableTargetInfo implements ChooserTargetInfo {
-        private final DisplayResolveInfo mSourceInfo;
-        private final ResolveInfo mBackupResolveInfo;
-        private final ChooserTarget mChooserTarget;
-        private final String mDisplayLabel;
-        private Drawable mBadgeIcon = null;
-        private CharSequence mBadgeContentDescription;
-        private Drawable mDisplayIcon;
-        private final Intent mFillInIntent;
-        private final int mFillInFlags;
-        private final float mModifiedScore;
-        private boolean mIsSuspended = false;
-
-        SelectableTargetInfo(DisplayResolveInfo sourceInfo, ChooserTarget chooserTarget,
-                float modifiedScore) {
-            mSourceInfo = sourceInfo;
-            mChooserTarget = chooserTarget;
-            mModifiedScore = modifiedScore;
-            if (sourceInfo != null) {
-                final ResolveInfo ri = sourceInfo.getResolveInfo();
-                if (ri != null) {
-                    final ActivityInfo ai = ri.activityInfo;
-                    if (ai != null && ai.applicationInfo != null) {
-                        final PackageManager pm = getPackageManager();
-                        mBadgeIcon = pm.getApplicationIcon(ai.applicationInfo);
-                        mBadgeContentDescription = pm.getApplicationLabel(ai.applicationInfo);
-                        mIsSuspended =
-                                (ai.applicationInfo.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
-                    }
-                }
-            }
-            // TODO(b/121287224): do this in the background thread, and only for selected targets
-            mDisplayIcon = getChooserTargetIconDrawable(chooserTarget);
-
-            if (sourceInfo != null) {
-                mBackupResolveInfo = null;
-            } else {
-                mBackupResolveInfo = getPackageManager().resolveActivity(getResolvedIntent(), 0);
-            }
-
-            mFillInIntent = null;
-            mFillInFlags = 0;
-
-            mDisplayLabel = sanitizeDisplayLabel(chooserTarget.getTitle());
-        }
-
-        private SelectableTargetInfo(SelectableTargetInfo other, Intent fillInIntent, int flags) {
-            mSourceInfo = other.mSourceInfo;
-            mBackupResolveInfo = other.mBackupResolveInfo;
-            mChooserTarget = other.mChooserTarget;
-            mBadgeIcon = other.mBadgeIcon;
-            mBadgeContentDescription = other.mBadgeContentDescription;
-            mDisplayIcon = other.mDisplayIcon;
-            mFillInIntent = fillInIntent;
-            mFillInFlags = flags;
-            mModifiedScore = other.mModifiedScore;
-
-            mDisplayLabel = sanitizeDisplayLabel(mChooserTarget.getTitle());
-        }
-
-        private String sanitizeDisplayLabel(CharSequence label) {
-            SpannableStringBuilder sb = new SpannableStringBuilder(label);
-            sb.clearSpans();
-            return sb.toString();
-        }
-
-        public boolean isSuspended() {
-            return mIsSuspended;
-        }
-
-        /**
-         * Since ShortcutInfos are returned by ShortcutManager, we can cache the shortcuts and skip
-         * the call to LauncherApps#getShortcuts(ShortcutQuery).
-         */
-        // TODO(121287224): Refactor code to apply the suggestion above
-        private Drawable getChooserTargetIconDrawable(ChooserTarget target) {
-            Drawable directShareIcon = null;
-
-            // First get the target drawable and associated activity info
-            final Icon icon = target.getIcon();
-            if (icon != null) {
-                directShareIcon = icon.loadDrawable(ChooserActivity.this);
-            } else if (USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS) {
-                Bundle extras = target.getIntentExtras();
-                if (extras != null && extras.containsKey(Intent.EXTRA_SHORTCUT_ID)) {
-                    CharSequence shortcutId = extras.getCharSequence(Intent.EXTRA_SHORTCUT_ID);
-                    LauncherApps launcherApps = (LauncherApps) getSystemService(
-                            Context.LAUNCHER_APPS_SERVICE);
-                    final LauncherApps.ShortcutQuery q = new LauncherApps.ShortcutQuery();
-                    q.setPackage(target.getComponentName().getPackageName());
-                    q.setShortcutIds(Arrays.asList(shortcutId.toString()));
-                    q.setQueryFlags(LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC);
-                    final List<ShortcutInfo> shortcuts = launcherApps.getShortcuts(q, getUser());
-                    if (shortcuts != null && shortcuts.size() > 0) {
-                        directShareIcon = launcherApps.getShortcutIconDrawable(shortcuts.get(0), 0);
-                    }
-                }
-            }
-
-            if (directShareIcon == null) return null;
-
-            ActivityInfo info = null;
-            try {
-                info = mPm.getActivityInfo(target.getComponentName(), 0);
-            } catch (NameNotFoundException error) {
-                Log.e(TAG, "Could not find activity associated with ChooserTarget");
-            }
-
-            if (info == null) return null;
-
-            // Now fetch app icon and raster with no badging even in work profile
-            Bitmap appIcon = makePresentationGetter(info).getIconBitmap(
-                    UserHandle.getUserHandleForUid(UserHandle.myUserId()));
-
-            // Raster target drawable with appIcon as a badge
-            SimpleIconFactory sif = SimpleIconFactory.obtain(ChooserActivity.this);
-            Bitmap directShareBadgedIcon = sif.createAppBadgedIconBitmap(directShareIcon, appIcon);
-            sif.recycle();
-
-            return new BitmapDrawable(getResources(), directShareBadgedIcon);
-        }
-
-        public float getModifiedScore() {
-            return mModifiedScore;
-        }
-
-        @Override
-        public Intent getResolvedIntent() {
-            if (mSourceInfo != null) {
-                return mSourceInfo.getResolvedIntent();
-            }
-
-            final Intent targetIntent = new Intent(getTargetIntent());
-            targetIntent.setComponent(mChooserTarget.getComponentName());
-            targetIntent.putExtras(mChooserTarget.getIntentExtras());
-            return targetIntent;
-        }
-
-        @Override
-        public ComponentName getResolvedComponentName() {
-            if (mSourceInfo != null) {
-                return mSourceInfo.getResolvedComponentName();
-            } else if (mBackupResolveInfo != null) {
-                return new ComponentName(mBackupResolveInfo.activityInfo.packageName,
-                        mBackupResolveInfo.activityInfo.name);
-            }
-            return null;
-        }
-
-        private Intent getBaseIntentToSend() {
-            Intent result = getResolvedIntent();
-            if (result == null) {
-                Log.e(TAG, "ChooserTargetInfo: no base intent available to send");
-            } else {
-                result = new Intent(result);
-                if (mFillInIntent != null) {
-                    result.fillIn(mFillInIntent, mFillInFlags);
-                }
-                result.fillIn(mReferrerFillInIntent, 0);
-            }
-            return result;
-        }
-
-        @Override
-        public boolean start(Activity activity, Bundle options) {
-            throw new RuntimeException("ChooserTargets should be started as caller.");
-        }
-
-        @Override
-        public boolean startAsCaller(ResolverActivity activity, Bundle options, int userId) {
-            final Intent intent = getBaseIntentToSend();
-            if (intent == null) {
-                return false;
-            }
-            intent.setComponent(mChooserTarget.getComponentName());
-            intent.putExtras(mChooserTarget.getIntentExtras());
-
-            // Important: we will ignore the target security checks in ActivityManager
-            // if and only if the ChooserTarget's target package is the same package
-            // where we got the ChooserTargetService that provided it. This lets a
-            // ChooserTargetService provide a non-exported or permission-guarded target
-            // to the chooser for the user to pick.
-            //
-            // If mSourceInfo is null, we got this ChooserTarget from the caller or elsewhere
-            // so we'll obey the caller's normal security checks.
-            final boolean ignoreTargetSecurity = mSourceInfo != null
-                    && mSourceInfo.getResolvedComponentName().getPackageName()
-                    .equals(mChooserTarget.getComponentName().getPackageName());
-            return activity.startAsCallerImpl(intent, options, ignoreTargetSecurity, userId);
-        }
-
-        @Override
-        public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
-            throw new RuntimeException("ChooserTargets should be started as caller.");
-        }
-
-        @Override
-        public ResolveInfo getResolveInfo() {
-            return mSourceInfo != null ? mSourceInfo.getResolveInfo() : mBackupResolveInfo;
-        }
-
-        @Override
-        public CharSequence getDisplayLabel() {
-            return mDisplayLabel;
-        }
-
-        @Override
-        public CharSequence getExtendedInfo() {
-            // ChooserTargets have badge icons, so we won't show the extended info to disambiguate.
-            return null;
-        }
-
-        @Override
-        public Drawable getDisplayIcon() {
-            return mDisplayIcon;
-        }
-
-        public ChooserTarget getChooserTarget() {
-            return mChooserTarget;
-        }
-
-        @Override
-        public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
-            return new SelectableTargetInfo(this, fillInIntent, flags);
-        }
-
-        @Override
-        public List<Intent> getAllSourceIntents() {
-            final List<Intent> results = new ArrayList<>();
-            if (mSourceInfo != null) {
-                // We only queried the service for the first one in our sourceinfo.
-                results.add(mSourceInfo.getAllSourceIntents().get(0));
-            }
-            return results;
-        }
-    }
-
     private void handleScroll(View view, int x, int y, int oldx, int oldy) {
         if (mChooserRowAdapter != null) {
             mChooserRowAdapter.handleScroll(view, y, oldy);
@@ -2408,7 +2063,8 @@
 
                 boolean isExpandable = getResources().getConfiguration().orientation
                         == Configuration.ORIENTATION_PORTRAIT && !isInMultiWindowMode();
-                if (directShareHeight != 0 && isSendAction(getTargetIntent()) && isExpandable) {
+                if (directShareHeight != 0 && isSendAction(getTargetIntent())
+                        && isExpandable) {
                     // make sure to leave room for direct share 4->8 expansion
                     int requiredExpansionHeight =
                             (int) (directShareHeight / DIRECT_SHARE_EXPANSION_RATE);
@@ -2424,485 +2080,6 @@
         }
     }
 
-    public class ChooserListAdapter extends ResolveListAdapter {
-        public static final int TARGET_BAD = -1;
-        public static final int TARGET_CALLER = 0;
-        public static final int TARGET_SERVICE = 1;
-        public static final int TARGET_STANDARD = 2;
-        public static final int TARGET_STANDARD_AZ = 3;
-
-        private static final int MAX_SUGGESTED_APP_TARGETS = 4;
-        private static final int MAX_CHOOSER_TARGETS_PER_APP = 2;
-
-        private static final int MAX_SERVICE_TARGETS = 8;
-
-        private final int mMaxShortcutTargetsPerApp =
-                getResources().getInteger(R.integer.config_maxShortcutTargetsPerApp);
-
-        private int mNumShortcutResults = 0;
-
-        // Reserve spots for incoming direct share targets by adding placeholders
-        private ChooserTargetInfo mPlaceHolderTargetInfo = new PlaceHolderTargetInfo();
-        private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
-        private final List<TargetInfo> mCallerTargets = new ArrayList<>();
-
-        private final BaseChooserTargetComparator mBaseTargetComparator
-                = new BaseChooserTargetComparator();
-
-        public ChooserListAdapter(Context context, List<Intent> payloadIntents,
-                Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid,
-                boolean filterLastUsed, ResolverListController resolverListController) {
-            // Don't send the initial intents through the shared ResolverActivity path,
-            // we want to separate them into a different section.
-            super(context, payloadIntents, null, rList, launchedFromUid, filterLastUsed,
-                    resolverListController);
-
-            createPlaceHolders();
-
-            if (initialIntents != null) {
-                final PackageManager pm = getPackageManager();
-                for (int i = 0; i < initialIntents.length; i++) {
-                    final Intent ii = initialIntents[i];
-                    if (ii == null) {
-                        continue;
-                    }
-
-                    // We reimplement Intent#resolveActivityInfo here because if we have an
-                    // implicit intent, we want the ResolveInfo returned by PackageManager
-                    // instead of one we reconstruct ourselves. The ResolveInfo returned might
-                    // have extra metadata and resolvePackageName set and we want to respect that.
-                    ResolveInfo ri = null;
-                    ActivityInfo ai = null;
-                    final ComponentName cn = ii.getComponent();
-                    if (cn != null) {
-                        try {
-                            ai = pm.getActivityInfo(ii.getComponent(), 0);
-                            ri = new ResolveInfo();
-                            ri.activityInfo = ai;
-                        } catch (PackageManager.NameNotFoundException ignored) {
-                            // ai will == null below
-                        }
-                    }
-                    if (ai == null) {
-                        ri = pm.resolveActivity(ii, PackageManager.MATCH_DEFAULT_ONLY);
-                        ai = ri != null ? ri.activityInfo : null;
-                    }
-                    if (ai == null) {
-                        Log.w(TAG, "No activity found for " + ii);
-                        continue;
-                    }
-                    UserManager userManager =
-                            (UserManager) getSystemService(Context.USER_SERVICE);
-                    if (ii instanceof LabeledIntent) {
-                        LabeledIntent li = (LabeledIntent) ii;
-                        ri.resolvePackageName = li.getSourcePackage();
-                        ri.labelRes = li.getLabelResource();
-                        ri.nonLocalizedLabel = li.getNonLocalizedLabel();
-                        ri.icon = li.getIconResource();
-                        ri.iconResourceId = ri.icon;
-                    }
-                    if (userManager.isManagedProfile()) {
-                        ri.noResourceId = true;
-                        ri.icon = 0;
-                    }
-                    ResolveInfoPresentationGetter getter = makePresentationGetter(ri);
-                    mCallerTargets.add(new DisplayResolveInfo(ii, ri,
-                            getter.getLabel(), getter.getSubLabel(), ii));
-                }
-            }
-        }
-
-        @Override
-        public void handlePackagesChanged() {
-            if (DEBUG) {
-                Log.d(TAG, "clearing queryTargets on package change");
-            }
-            createPlaceHolders();
-            mServicesRequested.clear();
-            notifyDataSetChanged();
-
-            super.handlePackagesChanged();
-        }
-
-        @Override
-        public void notifyDataSetChanged() {
-            if (!mListViewDataChanged) {
-                mChooserHandler.sendEmptyMessageDelayed(ChooserHandler.LIST_VIEW_UPDATE_MESSAGE,
-                        LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);
-                mListViewDataChanged = true;
-            }
-        }
-
-        private void refreshListView() {
-            if (mListViewDataChanged) {
-                super.notifyDataSetChanged();
-            }
-            mListViewDataChanged = false;
-        }
-
-
-        private void createPlaceHolders() {
-            mNumShortcutResults = 0;
-            mServiceTargets.clear();
-            for (int i = 0; i < MAX_SERVICE_TARGETS; i++) {
-                mServiceTargets.add(mPlaceHolderTargetInfo);
-            }
-        }
-
-        @Override
-        public View onCreateView(ViewGroup parent) {
-            return mInflater.inflate(
-                    com.android.internal.R.layout.resolve_grid_item, parent, false);
-        }
-
-        @Override
-        protected void onBindView(View view, TargetInfo info) {
-            super.onBindView(view, info);
-
-            // If target is loading, show a special placeholder shape in the label, make unclickable
-            final ViewHolder holder = (ViewHolder) view.getTag();
-            if (info instanceof PlaceHolderTargetInfo) {
-                final int maxWidth = getResources().getDimensionPixelSize(
-                        R.dimen.chooser_direct_share_label_placeholder_max_width);
-                holder.text.setMaxWidth(maxWidth);
-                holder.text.setBackground(getResources().getDrawable(
-                        R.drawable.chooser_direct_share_label_placeholder, getTheme()));
-                // Prevent rippling by removing background containing ripple
-                holder.itemView.setBackground(null);
-            } else {
-                holder.text.setMaxWidth(Integer.MAX_VALUE);
-                holder.text.setBackground(null);
-                holder.itemView.setBackground(holder.defaultItemViewBackground);
-            }
-        }
-
-        /**
-         * Rather than fully sorting the input list, this sorting task will put the top k elements
-         * in the head of input list and fill the tail with other elements in undetermined order.
-         */
-        @Override
-        AsyncTask<List<ResolvedComponentInfo>,
-                Void,
-                List<ResolvedComponentInfo>> createSortingTask() {
-            return new AsyncTask<List<ResolvedComponentInfo>,
-                    Void,
-                    List<ResolvedComponentInfo>>() {
-                @Override
-                protected List<ResolvedComponentInfo> doInBackground(
-                        List<ResolvedComponentInfo>... params) {
-                    mResolverListController.topK(params[0],
-                            getMaxRankedTargets());
-                    return params[0];
-                }
-
-                @Override
-                protected void onPostExecute(List<ResolvedComponentInfo> sortedComponents) {
-                    processSortedList(sortedComponents);
-                    bindProfileView();
-                    notifyDataSetChanged();
-                }
-            };
-        }
-
-        @Override
-        public void onListRebuilt() {
-            updateAlphabeticalList();
-
-            // don't support direct share on low ram devices
-            if (ActivityManager.isLowRamDeviceStatic()) {
-                return;
-            }
-
-            if (USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS
-                        || USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) {
-                if (DEBUG) {
-                    Log.d(TAG, "querying direct share targets from ShortcutManager");
-                }
-
-                queryDirectShareTargets(this, false);
-            }
-            if (USE_CHOOSER_TARGET_SERVICE_FOR_DIRECT_TARGETS) {
-                if (DEBUG) {
-                    Log.d(TAG, "List built querying services");
-                }
-
-                queryTargetServices(this);
-            }
-        }
-
-        @Override
-        public boolean shouldGetResolvedFilter() {
-            return true;
-        }
-
-        @Override
-        public int getCount() {
-            return getRankedTargetCount() + getAlphaTargetCount()
-                    + getSelectableServiceTargetCount() + getCallerTargetCount();
-        }
-
-        @Override
-        public int getUnfilteredCount() {
-            int appTargets = super.getUnfilteredCount();
-            if (appTargets > getMaxRankedTargets()) {
-                appTargets = appTargets + getMaxRankedTargets();
-            }
-            return appTargets + getSelectableServiceTargetCount() + getCallerTargetCount();
-        }
-
-
-        public int getCallerTargetCount() {
-            return Math.min(mCallerTargets.size(), MAX_SUGGESTED_APP_TARGETS);
-        }
-
-        /**
-          * Filter out placeholders and non-selectable service targets
-          */
-        public int getSelectableServiceTargetCount() {
-            int count = 0;
-            for (ChooserTargetInfo info : mServiceTargets) {
-                if (info instanceof SelectableTargetInfo) {
-                    count++;
-                }
-            }
-            return count;
-        }
-
-        public int getServiceTargetCount() {
-            if (isSendAction(getTargetIntent()) && !ActivityManager.isLowRamDeviceStatic()) {
-                return Math.min(mServiceTargets.size(), MAX_SERVICE_TARGETS);
-            }
-
-            return 0;
-        }
-
-        int getAlphaTargetCount() {
-            int standardCount = super.getCount();
-            return standardCount > getMaxRankedTargets() ? standardCount : 0;
-        }
-
-        int getRankedTargetCount() {
-            int spacesAvailable = getMaxRankedTargets() - getCallerTargetCount();
-            return Math.min(spacesAvailable, super.getCount());
-        }
-
-        private int getMaxRankedTargets() {
-            return mChooserRowAdapter == null ? 4 : mChooserRowAdapter.getMaxTargetsPerRow();
-        }
-
-        public int getPositionTargetType(int position) {
-            int offset = 0;
-
-            final int serviceTargetCount = getServiceTargetCount();
-            if (position < serviceTargetCount) {
-                return TARGET_SERVICE;
-            }
-            offset += serviceTargetCount;
-
-            final int callerTargetCount = getCallerTargetCount();
-            if (position - offset < callerTargetCount) {
-                return TARGET_CALLER;
-            }
-            offset += callerTargetCount;
-
-            final int rankedTargetCount = getRankedTargetCount();
-            if (position - offset < rankedTargetCount) {
-                return TARGET_STANDARD;
-            }
-            offset += rankedTargetCount;
-
-            final int standardTargetCount = getAlphaTargetCount();
-            if (position - offset < standardTargetCount) {
-                return TARGET_STANDARD_AZ;
-            }
-
-            return TARGET_BAD;
-        }
-
-        @Override
-        public TargetInfo getItem(int position) {
-            return targetInfoForPosition(position, true);
-        }
-
-
-        /**
-         * Find target info for a given position.
-         * Since ChooserActivity displays several sections of content, determine which
-         * section provides this item.
-         */
-        @Override
-        public TargetInfo targetInfoForPosition(int position, boolean filtered) {
-            int offset = 0;
-
-            // Direct share targets
-            final int serviceTargetCount = filtered ? getServiceTargetCount() :
-                                               getSelectableServiceTargetCount();
-            if (position < serviceTargetCount) {
-                return mServiceTargets.get(position);
-            }
-            offset += serviceTargetCount;
-
-            // Targets provided by calling app
-            final int callerTargetCount = getCallerTargetCount();
-            if (position - offset < callerTargetCount) {
-                return mCallerTargets.get(position - offset);
-            }
-            offset += callerTargetCount;
-
-            // Ranked standard app targets
-            final int rankedTargetCount = getRankedTargetCount();
-            if (position - offset < rankedTargetCount) {
-                return filtered ? super.getItem(position - offset)
-                        : getDisplayResolveInfo(position - offset);
-            }
-            offset += rankedTargetCount;
-
-            // Alphabetical complete app target list.
-            if (position - offset < getAlphaTargetCount() && !mSortedList.isEmpty()) {
-                return mSortedList.get(position - offset);
-            }
-
-            return null;
-        }
-
-
-        /**
-         * Evaluate targets for inclusion in the direct share area. May not be included
-         * if score is too low.
-         */
-        public void addServiceResults(DisplayResolveInfo origTarget, List<ChooserTarget> targets,
-                @ShareTargetType int targetType) {
-            if (DEBUG) {
-                Log.d(TAG, "addServiceResults " + origTarget + ", " + targets.size()
-                        + " targets");
-            }
-
-            if (targets.size() == 0) {
-                return;
-            }
-
-            final float baseScore = getBaseScore(origTarget, targetType);
-            Collections.sort(targets, mBaseTargetComparator);
-
-            final boolean isShortcutResult =
-                    (targetType == TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER
-                            || targetType == TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE);
-            final int maxTargets = isShortcutResult ? mMaxShortcutTargetsPerApp
-                                       : MAX_CHOOSER_TARGETS_PER_APP;
-            float lastScore = 0;
-            boolean shouldNotify = false;
-            for (int i = 0, count = Math.min(targets.size(), maxTargets); i < count; i++) {
-                final ChooserTarget target = targets.get(i);
-                float targetScore = target.getScore();
-                targetScore *= baseScore;
-                if (i > 0 && targetScore >= lastScore) {
-                    // Apply a decay so that the top app can't crowd out everything else.
-                    // This incents ChooserTargetServices to define what's truly better.
-                    targetScore = lastScore * 0.95f;
-                }
-                boolean isInserted = insertServiceTarget(
-                        new SelectableTargetInfo(origTarget, target, targetScore));
-
-                if (isInserted && isShortcutResult) {
-                    mNumShortcutResults++;
-                }
-
-                shouldNotify |= isInserted;
-
-                if (DEBUG) {
-                    Log.d(TAG, " => " + target.toString() + " score=" + targetScore
-                            + " base=" + target.getScore()
-                            + " lastScore=" + lastScore
-                            + " baseScore=" + baseScore);
-                }
-
-                lastScore = targetScore;
-            }
-
-            if (shouldNotify) {
-                notifyDataSetChanged();
-            }
-        }
-
-        private int getNumShortcutResults() {
-            return mNumShortcutResults;
-        }
-
-        /**
-          * Use the scoring system along with artificial boosts to create up to 4 distinct buckets:
-          * <ol>
-          *   <li>App-supplied targets
-          *   <li>Shortcuts ranked via App Prediction Manager
-          *   <li>Shortcuts ranked via legacy heuristics
-          *   <li>Legacy direct share targets
-          * </ol>
-          */
-        public float getBaseScore(DisplayResolveInfo target, @ShareTargetType int targetType) {
-            if (target == null) {
-                return CALLER_TARGET_SCORE_BOOST;
-            }
-
-            if (targetType == TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE) {
-                return SHORTCUT_TARGET_SCORE_BOOST;
-            }
-
-            float score = super.getScore(target);
-            if (targetType == TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER) {
-                return score * SHORTCUT_TARGET_SCORE_BOOST;
-            }
-
-            return score;
-        }
-
-        /**
-         * Calling this marks service target loading complete, and will attempt to no longer
-         * update the direct share area.
-         */
-        public void completeServiceTargetLoading() {
-            mServiceTargets.removeIf(o -> o instanceof PlaceHolderTargetInfo);
-
-            if (mServiceTargets.isEmpty()) {
-                mServiceTargets.add(new EmptyTargetInfo());
-            }
-            notifyDataSetChanged();
-        }
-
-        private boolean insertServiceTarget(ChooserTargetInfo chooserTargetInfo) {
-            // Avoid inserting any potentially late results
-            if (mServiceTargets.size() == 1
-                    && mServiceTargets.get(0) instanceof EmptyTargetInfo) {
-                return false;
-            }
-
-            // Check for duplicates and abort if found
-            for (ChooserTargetInfo otherTargetInfo : mServiceTargets) {
-                if (chooserTargetInfo.isSimilar(otherTargetInfo)) {
-                    return false;
-                }
-            }
-
-            int currentSize = mServiceTargets.size();
-            final float newScore = chooserTargetInfo.getModifiedScore();
-            for (int i = 0; i < Math.min(currentSize, MAX_SERVICE_TARGETS); i++) {
-                final ChooserTargetInfo serviceTarget = mServiceTargets.get(i);
-                if (serviceTarget == null) {
-                    mServiceTargets.set(i, chooserTargetInfo);
-                    return true;
-                } else if (newScore > serviceTarget.getModifiedScore()) {
-                    mServiceTargets.add(i, chooserTargetInfo);
-                    return true;
-                }
-            }
-
-            if (currentSize < MAX_SERVICE_TARGETS) {
-                mServiceTargets.add(chooserTargetInfo);
-                return true;
-            }
-
-            return false;
-        }
-    }
-
     static class BaseChooserTargetComparator implements Comparator<ChooserTarget> {
         @Override
         public int compare(ChooserTarget lhs, ChooserTarget rhs) {
@@ -2911,8 +2088,77 @@
         }
     }
 
+    @Override // ResolverListCommunicator
+    public void onHandlePackagesChanged() {
+        mServicesRequested.clear();
+        mAdapter.notifyDataSetChanged();
+        super.onHandlePackagesChanged();
+    }
 
-    private boolean isSendAction(Intent targetIntent) {
+    @Override // SelectableTargetInfoCommunicator
+    public ActivityInfoPresentationGetter makePresentationGetter(ActivityInfo info) {
+        return mChooserListAdapter.makePresentationGetter(info);
+    }
+
+    @Override // SelectableTargetInfoCommunicator
+    public Intent getReferrerFillInIntent() {
+        return mReferrerFillInIntent;
+    }
+
+    @Override // ChooserListCommunicator
+    public int getMaxRankedTargets() {
+        return mChooserRowAdapter == null ? 4 : mChooserRowAdapter.getMaxTargetsPerRow();
+    }
+
+    @Override // ChooserListCommunicator
+    public void sendListViewUpdateMessage() {
+        mChooserHandler.sendEmptyMessageDelayed(ChooserHandler.LIST_VIEW_UPDATE_MESSAGE,
+                LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);
+    }
+
+    @Override
+    public void onListRebuilt() {
+        if (mChooserListAdapter.mDisplayList == null
+                || mChooserListAdapter.mDisplayList.isEmpty()) {
+            mChooserListAdapter.notifyDataSetChanged();
+        } else {
+            new AsyncTask<Void, Void, Void>() {
+                @Override
+                protected Void doInBackground(Void... voids) {
+                    mChooserListAdapter.updateAlphabeticalList();
+                    return null;
+                }
+                @Override
+                protected void onPostExecute(Void aVoid) {
+                    mChooserListAdapter.notifyDataSetChanged();
+                }
+            }.execute();
+        }
+
+        // don't support direct share on low ram devices
+        if (ActivityManager.isLowRamDeviceStatic()) {
+            return;
+        }
+
+        if (ChooserFlags.USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS
+                || ChooserFlags.USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) {
+            if (DEBUG) {
+                Log.d(TAG, "querying direct share targets from ShortcutManager");
+            }
+
+            queryDirectShareTargets(mChooserListAdapter, false);
+        }
+        if (USE_CHOOSER_TARGET_SERVICE_FOR_DIRECT_TARGETS) {
+            if (DEBUG) {
+                Log.d(TAG, "List built querying services");
+            }
+
+            queryTargetServices(mChooserListAdapter);
+        }
+    }
+
+    @Override // ChooserListCommunicator
+    public boolean isSendAction(Intent targetIntent) {
         if (targetIntent == null) {
             return false;
         }
@@ -3067,7 +2313,8 @@
         // There can be at most one row in the listview, that is internally
         // a ViewGroup with 2 rows
         public int getServiceTargetRowCount() {
-            if (isSendAction(getTargetIntent()) && !ActivityManager.isLowRamDeviceStatic()) {
+            if (isSendAction(getTargetIntent())
+                    && !ActivityManager.isLowRamDeviceStatic()) {
                 return 1;
             }
             return 0;
@@ -3164,7 +2411,7 @@
                     getResources().getDrawable(R.drawable.chooser_row_layer_list, null));
             mProfileView = profileRow.findViewById(R.id.profile_button);
             mProfileView.setOnClickListener(ChooserActivity.this::onProfileClick);
-            bindProfileView();
+            updateProfileViewButton();
             return profileRow;
         }
 
diff --git a/core/java/com/android/internal/app/ChooserFlags.java b/core/java/com/android/internal/app/ChooserFlags.java
new file mode 100644
index 0000000..f1f1dbf
--- /dev/null
+++ b/core/java/com/android/internal/app/ChooserFlags.java
@@ -0,0 +1,38 @@
+/*
+ * 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.internal.app;
+
+import android.app.prediction.AppPredictionManager;
+
+/**
+ * Common flags for {@link ChooserListAdapter} and {@link ChooserActivity}.
+ */
+public class ChooserFlags {
+    /**
+     * If set to true, use ShortcutManager to retrieve the matching direct share targets, instead of
+     * binding to every ChooserTargetService implementation.
+     */
+    // TODO(b/121287573): Replace with a system flag (setprop?)
+    public static final boolean USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS = true;
+
+    /**
+     * If {@link ChooserFlags#USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS} and this is set to true,
+     * {@link AppPredictionManager} will be queried for direct share targets.
+     */
+    // TODO(b/123089490): Replace with system flag
+    static final boolean USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS = true;
+}
diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java
new file mode 100644
index 0000000..38f4c64
--- /dev/null
+++ b/core/java/com/android/internal/app/ChooserListAdapter.java
@@ -0,0 +1,539 @@
+/*
+ * 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.internal.app;
+
+import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE;
+import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.LabeledIntent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.AsyncTask;
+import android.os.UserManager;
+import android.service.chooser.ChooserTarget;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.internal.R;
+import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
+import com.android.internal.app.chooser.ChooserTargetInfo;
+import com.android.internal.app.chooser.DisplayResolveInfo;
+import com.android.internal.app.chooser.SelectableTargetInfo;
+import com.android.internal.app.chooser.TargetInfo;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class ChooserListAdapter extends ResolverListAdapter {
+    private static final String TAG = "ChooserListAdapter";
+    private static final boolean DEBUG = false;
+
+    public static final int TARGET_BAD = -1;
+    public static final int TARGET_CALLER = 0;
+    public static final int TARGET_SERVICE = 1;
+    public static final int TARGET_STANDARD = 2;
+    public static final int TARGET_STANDARD_AZ = 3;
+
+    private static final int MAX_SUGGESTED_APP_TARGETS = 4;
+    private static final int MAX_CHOOSER_TARGETS_PER_APP = 2;
+
+    static final int MAX_SERVICE_TARGETS = 8;
+
+    /** {@link #getBaseScore} */
+    public static final float CALLER_TARGET_SCORE_BOOST = 900.f;
+    /** {@link #getBaseScore} */
+    public static final float SHORTCUT_TARGET_SCORE_BOOST = 90.f;
+
+    private final int mMaxShortcutTargetsPerApp;
+    private final ChooserListCommunicator mChooserListCommunicator;
+    private final SelectableTargetInfo.SelectableTargetInfoCommunicator
+            mSelectableTargetInfoComunicator;
+
+    private int mNumShortcutResults = 0;
+
+    // Reserve spots for incoming direct share targets by adding placeholders
+    private ChooserTargetInfo
+            mPlaceHolderTargetInfo = new ChooserActivity.PlaceHolderTargetInfo();
+    private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
+    private final List<TargetInfo> mCallerTargets = new ArrayList<>();
+
+    private final ChooserActivity.BaseChooserTargetComparator mBaseTargetComparator =
+            new ChooserActivity.BaseChooserTargetComparator();
+    private boolean mListViewDataChanged = false;
+
+    // Sorted list of DisplayResolveInfos for the alphabetical app section.
+    private List<DisplayResolveInfo> mSortedList = new ArrayList<>();
+
+    public ChooserListAdapter(Context context, List<Intent> payloadIntents,
+            Intent[] initialIntents, List<ResolveInfo> rList,
+            boolean filterLastUsed, ResolverListController resolverListController,
+            boolean useLayoutForBrowsables,
+            ChooserListCommunicator chooserListCommunicator,
+            SelectableTargetInfo.SelectableTargetInfoCommunicator selectableTargetInfoComunicator) {
+        // Don't send the initial intents through the shared ResolverActivity path,
+        // we want to separate them into a different section.
+        super(context, payloadIntents, null, rList, filterLastUsed,
+                resolverListController, useLayoutForBrowsables,
+                chooserListCommunicator, false);
+
+        createPlaceHolders();
+        mMaxShortcutTargetsPerApp =
+                context.getResources().getInteger(R.integer.config_maxShortcutTargetsPerApp);
+        mChooserListCommunicator = chooserListCommunicator;
+        mSelectableTargetInfoComunicator = selectableTargetInfoComunicator;
+
+        if (initialIntents != null) {
+            final PackageManager pm = context.getPackageManager();
+            for (int i = 0; i < initialIntents.length; i++) {
+                final Intent ii = initialIntents[i];
+                if (ii == null) {
+                    continue;
+                }
+
+                // We reimplement Intent#resolveActivityInfo here because if we have an
+                // implicit intent, we want the ResolveInfo returned by PackageManager
+                // instead of one we reconstruct ourselves. The ResolveInfo returned might
+                // have extra metadata and resolvePackageName set and we want to respect that.
+                ResolveInfo ri = null;
+                ActivityInfo ai = null;
+                final ComponentName cn = ii.getComponent();
+                if (cn != null) {
+                    try {
+                        ai = pm.getActivityInfo(ii.getComponent(), 0);
+                        ri = new ResolveInfo();
+                        ri.activityInfo = ai;
+                    } catch (PackageManager.NameNotFoundException ignored) {
+                        // ai will == null below
+                    }
+                }
+                if (ai == null) {
+                    ri = pm.resolveActivity(ii, PackageManager.MATCH_DEFAULT_ONLY);
+                    ai = ri != null ? ri.activityInfo : null;
+                }
+                if (ai == null) {
+                    Log.w(TAG, "No activity found for " + ii);
+                    continue;
+                }
+                UserManager userManager =
+                        (UserManager) context.getSystemService(Context.USER_SERVICE);
+                if (ii instanceof LabeledIntent) {
+                    LabeledIntent li = (LabeledIntent) ii;
+                    ri.resolvePackageName = li.getSourcePackage();
+                    ri.labelRes = li.getLabelResource();
+                    ri.nonLocalizedLabel = li.getNonLocalizedLabel();
+                    ri.icon = li.getIconResource();
+                    ri.iconResourceId = ri.icon;
+                }
+                if (userManager.isManagedProfile()) {
+                    ri.noResourceId = true;
+                    ri.icon = 0;
+                }
+                mCallerTargets.add(new DisplayResolveInfo(ii, ri, ii, makePresentationGetter(ri)));
+            }
+        }
+    }
+
+    @Override
+    public void handlePackagesChanged() {
+        if (DEBUG) {
+            Log.d(TAG, "clearing queryTargets on package change");
+        }
+        createPlaceHolders();
+        mChooserListCommunicator.onHandlePackagesChanged();
+
+    }
+
+    @Override
+    public void notifyDataSetChanged() {
+        if (!mListViewDataChanged) {
+            mChooserListCommunicator.sendListViewUpdateMessage();
+            mListViewDataChanged = true;
+        }
+    }
+
+    void refreshListView() {
+        if (mListViewDataChanged) {
+            super.notifyDataSetChanged();
+        }
+        mListViewDataChanged = false;
+    }
+
+
+    private void createPlaceHolders() {
+        mNumShortcutResults = 0;
+        mServiceTargets.clear();
+        for (int i = 0; i < MAX_SERVICE_TARGETS; i++) {
+            mServiceTargets.add(mPlaceHolderTargetInfo);
+        }
+    }
+
+    @Override
+    public View onCreateView(ViewGroup parent) {
+        return mInflater.inflate(
+                com.android.internal.R.layout.resolve_grid_item, parent, false);
+    }
+
+    @Override
+    protected void onBindView(View view, TargetInfo info) {
+        super.onBindView(view, info);
+
+        // If target is loading, show a special placeholder shape in the label, make unclickable
+        final ViewHolder holder = (ViewHolder) view.getTag();
+        if (info instanceof ChooserActivity.PlaceHolderTargetInfo) {
+            final int maxWidth = mContext.getResources().getDimensionPixelSize(
+                    R.dimen.chooser_direct_share_label_placeholder_max_width);
+            holder.text.setMaxWidth(maxWidth);
+            holder.text.setBackground(mContext.getResources().getDrawable(
+                    R.drawable.chooser_direct_share_label_placeholder, mContext.getTheme()));
+            // Prevent rippling by removing background containing ripple
+            holder.itemView.setBackground(null);
+        } else {
+            holder.text.setMaxWidth(Integer.MAX_VALUE);
+            holder.text.setBackground(null);
+            holder.itemView.setBackground(holder.defaultItemViewBackground);
+        }
+    }
+
+    void updateAlphabeticalList() {
+        mSortedList.clear();
+        mSortedList.addAll(mDisplayList);
+        Collections.sort(mSortedList, new ChooserActivity.AzInfoComparator(mContext));
+    }
+
+    @Override
+    public boolean shouldGetResolvedFilter() {
+        return true;
+    }
+
+    @Override
+    public int getCount() {
+        return getRankedTargetCount() + getAlphaTargetCount()
+                + getSelectableServiceTargetCount() + getCallerTargetCount();
+    }
+
+    @Override
+    public int getUnfilteredCount() {
+        int appTargets = super.getUnfilteredCount();
+        if (appTargets > mChooserListCommunicator.getMaxRankedTargets()) {
+            appTargets = appTargets + mChooserListCommunicator.getMaxRankedTargets();
+        }
+        return appTargets + getSelectableServiceTargetCount() + getCallerTargetCount();
+    }
+
+
+    public int getCallerTargetCount() {
+        return Math.min(mCallerTargets.size(), MAX_SUGGESTED_APP_TARGETS);
+    }
+
+    /**
+     * Filter out placeholders and non-selectable service targets
+     */
+    public int getSelectableServiceTargetCount() {
+        int count = 0;
+        for (ChooserTargetInfo info : mServiceTargets) {
+            if (info instanceof SelectableTargetInfo) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    public int getServiceTargetCount() {
+        if (mChooserListCommunicator.isSendAction(mChooserListCommunicator.getTargetIntent())
+                && !ActivityManager.isLowRamDeviceStatic()) {
+            return Math.min(mServiceTargets.size(), MAX_SERVICE_TARGETS);
+        }
+
+        return 0;
+    }
+
+    int getAlphaTargetCount() {
+        int standardCount = super.getCount();
+        return standardCount > mChooserListCommunicator.getMaxRankedTargets() ? standardCount : 0;
+    }
+
+    int getRankedTargetCount() {
+        int spacesAvailable =
+                mChooserListCommunicator.getMaxRankedTargets() - getCallerTargetCount();
+        return Math.min(spacesAvailable, super.getCount());
+    }
+
+    public int getPositionTargetType(int position) {
+        int offset = 0;
+
+        final int serviceTargetCount = getServiceTargetCount();
+        if (position < serviceTargetCount) {
+            return TARGET_SERVICE;
+        }
+        offset += serviceTargetCount;
+
+        final int callerTargetCount = getCallerTargetCount();
+        if (position - offset < callerTargetCount) {
+            return TARGET_CALLER;
+        }
+        offset += callerTargetCount;
+
+        final int rankedTargetCount = getRankedTargetCount();
+        if (position - offset < rankedTargetCount) {
+            return TARGET_STANDARD;
+        }
+        offset += rankedTargetCount;
+
+        final int standardTargetCount = getAlphaTargetCount();
+        if (position - offset < standardTargetCount) {
+            return TARGET_STANDARD_AZ;
+        }
+
+        return TARGET_BAD;
+    }
+
+    @Override
+    public TargetInfo getItem(int position) {
+        return targetInfoForPosition(position, true);
+    }
+
+
+    /**
+     * Find target info for a given position.
+     * Since ChooserActivity displays several sections of content, determine which
+     * section provides this item.
+     */
+    @Override
+    public TargetInfo targetInfoForPosition(int position, boolean filtered) {
+        int offset = 0;
+
+        // Direct share targets
+        final int serviceTargetCount = filtered ? getServiceTargetCount() :
+                getSelectableServiceTargetCount();
+        if (position < serviceTargetCount) {
+            return mServiceTargets.get(position);
+        }
+        offset += serviceTargetCount;
+
+        // Targets provided by calling app
+        final int callerTargetCount = getCallerTargetCount();
+        if (position - offset < callerTargetCount) {
+            return mCallerTargets.get(position - offset);
+        }
+        offset += callerTargetCount;
+
+        // Ranked standard app targets
+        final int rankedTargetCount = getRankedTargetCount();
+        if (position - offset < rankedTargetCount) {
+            return filtered ? super.getItem(position - offset)
+                    : getDisplayResolveInfo(position - offset);
+        }
+        offset += rankedTargetCount;
+
+        // Alphabetical complete app target list.
+        if (position - offset < getAlphaTargetCount() && !mSortedList.isEmpty()) {
+            return mSortedList.get(position - offset);
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Evaluate targets for inclusion in the direct share area. May not be included
+     * if score is too low.
+     */
+    public void addServiceResults(DisplayResolveInfo origTarget, List<ChooserTarget> targets,
+            @ChooserActivity.ShareTargetType int targetType) {
+        if (DEBUG) {
+            Log.d(TAG, "addServiceResults " + origTarget + ", " + targets.size()
+                    + " targets");
+        }
+
+        if (targets.size() == 0) {
+            return;
+        }
+
+        final float baseScore = getBaseScore(origTarget, targetType);
+        Collections.sort(targets, mBaseTargetComparator);
+
+        final boolean isShortcutResult =
+                (targetType == TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER
+                        || targetType == TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE);
+        final int maxTargets = isShortcutResult ? mMaxShortcutTargetsPerApp
+                : MAX_CHOOSER_TARGETS_PER_APP;
+        float lastScore = 0;
+        boolean shouldNotify = false;
+        for (int i = 0, count = Math.min(targets.size(), maxTargets); i < count; i++) {
+            final ChooserTarget target = targets.get(i);
+            float targetScore = target.getScore();
+            targetScore *= baseScore;
+            if (i > 0 && targetScore >= lastScore) {
+                // Apply a decay so that the top app can't crowd out everything else.
+                // This incents ChooserTargetServices to define what's truly better.
+                targetScore = lastScore * 0.95f;
+            }
+            boolean isInserted = insertServiceTarget(new SelectableTargetInfo(
+                    mContext, origTarget, target, targetScore, mSelectableTargetInfoComunicator));
+
+            if (isInserted && isShortcutResult) {
+                mNumShortcutResults++;
+            }
+
+            shouldNotify |= isInserted;
+
+            if (DEBUG) {
+                Log.d(TAG, " => " + target.toString() + " score=" + targetScore
+                        + " base=" + target.getScore()
+                        + " lastScore=" + lastScore
+                        + " baseScore=" + baseScore);
+            }
+
+            lastScore = targetScore;
+        }
+
+        if (shouldNotify) {
+            notifyDataSetChanged();
+        }
+    }
+
+    int getNumShortcutResults() {
+        return mNumShortcutResults;
+    }
+
+    /**
+     * Use the scoring system along with artificial boosts to create up to 4 distinct buckets:
+     * <ol>
+     *   <li>App-supplied targets
+     *   <li>Shortcuts ranked via App Prediction Manager
+     *   <li>Shortcuts ranked via legacy heuristics
+     *   <li>Legacy direct share targets
+     * </ol>
+     */
+    public float getBaseScore(
+            DisplayResolveInfo target,
+            @ChooserActivity.ShareTargetType int targetType) {
+        if (target == null) {
+            return CALLER_TARGET_SCORE_BOOST;
+        }
+
+        if (targetType == TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE) {
+            return SHORTCUT_TARGET_SCORE_BOOST;
+        }
+
+        float score = super.getScore(target);
+        if (targetType == TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER) {
+            return score * SHORTCUT_TARGET_SCORE_BOOST;
+        }
+
+        return score;
+    }
+
+    /**
+     * Calling this marks service target loading complete, and will attempt to no longer
+     * update the direct share area.
+     */
+    public void completeServiceTargetLoading() {
+        mServiceTargets.removeIf(o -> o instanceof ChooserActivity.PlaceHolderTargetInfo);
+
+        if (mServiceTargets.isEmpty()) {
+            mServiceTargets.add(new ChooserActivity.EmptyTargetInfo());
+        }
+        notifyDataSetChanged();
+    }
+
+    private boolean insertServiceTarget(ChooserTargetInfo chooserTargetInfo) {
+        // Avoid inserting any potentially late results
+        if (mServiceTargets.size() == 1
+                && mServiceTargets.get(0) instanceof ChooserActivity.EmptyTargetInfo) {
+            return false;
+        }
+
+        // Check for duplicates and abort if found
+        for (ChooserTargetInfo otherTargetInfo : mServiceTargets) {
+            if (chooserTargetInfo.isSimilar(otherTargetInfo)) {
+                return false;
+            }
+        }
+
+        int currentSize = mServiceTargets.size();
+        final float newScore = chooserTargetInfo.getModifiedScore();
+        for (int i = 0; i < Math.min(currentSize, MAX_SERVICE_TARGETS); i++) {
+            final ChooserTargetInfo serviceTarget = mServiceTargets.get(i);
+            if (serviceTarget == null) {
+                mServiceTargets.set(i, chooserTargetInfo);
+                return true;
+            } else if (newScore > serviceTarget.getModifiedScore()) {
+                mServiceTargets.add(i, chooserTargetInfo);
+                return true;
+            }
+        }
+
+        if (currentSize < MAX_SERVICE_TARGETS) {
+            mServiceTargets.add(chooserTargetInfo);
+            return true;
+        }
+
+        return false;
+    }
+
+    public ChooserTarget getChooserTargetForValue(int value) {
+        return mServiceTargets.get(value).getChooserTarget();
+    }
+
+    /**
+     * Rather than fully sorting the input list, this sorting task will put the top k elements
+     * in the head of input list and fill the tail with other elements in undetermined order.
+     */
+    @Override
+    AsyncTask<List<ResolvedComponentInfo>,
+                Void,
+                List<ResolvedComponentInfo>> createSortingTask() {
+        return new AsyncTask<List<ResolvedComponentInfo>,
+                Void,
+                List<ResolvedComponentInfo>>() {
+            @Override
+            protected List<ResolvedComponentInfo> doInBackground(
+                    List<ResolvedComponentInfo>... params) {
+                mResolverListController.topK(params[0],
+                        mChooserListCommunicator.getMaxRankedTargets());
+                return params[0];
+            }
+            @Override
+            protected void onPostExecute(List<ResolvedComponentInfo> sortedComponents) {
+                processSortedList(sortedComponents);
+                mChooserListCommunicator.updateProfileViewButton();
+                notifyDataSetChanged();
+            }
+        };
+    }
+
+    /**
+     * Necessary methods to communicate between {@link ChooserListAdapter}
+     * and {@link ChooserActivity}.
+     */
+    interface ChooserListCommunicator extends ResolverListCommunicator {
+
+        int getMaxRankedTargets();
+
+        void sendListViewUpdateMessage();
+
+        boolean isSendAction(Intent targetIntent);
+    }
+}
diff --git a/core/java/com/android/internal/app/DumpHeapActivity.java b/core/java/com/android/internal/app/DumpHeapActivity.java
deleted file mode 100644
index e04e870..0000000
--- a/core/java/com/android/internal/app/DumpHeapActivity.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.app;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.AlertDialog;
-import android.content.ActivityNotFoundException;
-import android.content.ClipData;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.util.DebugUtils;
-import android.util.Slog;
-
-/**
- * This activity is displayed when the system has collected a heap dump from
- * a large process and the user has selected to share it.
- */
-public class DumpHeapActivity extends Activity {
-    /** The process we are reporting */
-    public static final String KEY_PROCESS = "process";
-    /** The size limit the process reached */
-    public static final String KEY_SIZE = "size";
-    /** Whether the user initiated the dump or not. */
-    public static final String KEY_IS_USER_INITIATED = "is_user_initiated";
-    /** Whether the process is a system process (eg: Android System) or not. */
-    public static final String KEY_IS_SYSTEM_PROCESS = "is_system_process";
-    /** Optional name of package to directly launch */
-    public static final String KEY_DIRECT_LAUNCH = "direct_launch";
-
-    // Broadcast action to determine when to delete the current dump heap data.
-    public static final String ACTION_DELETE_DUMPHEAP = "com.android.server.am.DELETE_DUMPHEAP";
-
-    // Extra for above: delay delete of data, since the user is in the process of sharing it.
-    public static final String EXTRA_DELAY_DELETE = "delay_delete";
-
-    static final public Uri JAVA_URI = Uri.parse("content://com.android.server.heapdump/java");
-
-    String mProcess;
-    long mSize;
-    AlertDialog mDialog;
-    boolean mHandled = false;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        mProcess = getIntent().getStringExtra(KEY_PROCESS);
-        mSize = getIntent().getLongExtra(KEY_SIZE, 0);
-        final boolean isUserInitiated = getIntent().getBooleanExtra(KEY_IS_USER_INITIATED, false);
-        final boolean isSystemProcess = getIntent().getBooleanExtra(KEY_IS_SYSTEM_PROCESS, false);
-
-        String directLaunch = getIntent().getStringExtra(KEY_DIRECT_LAUNCH);
-        if (directLaunch != null) {
-            Intent intent = new Intent(ActivityManager.ACTION_REPORT_HEAP_LIMIT);
-            intent.setPackage(directLaunch);
-            ClipData clip = ClipData.newUri(getContentResolver(), "Heap Dump", JAVA_URI);
-            intent.setClipData(clip);
-            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-            intent.setType(clip.getDescription().getMimeType(0));
-            intent.putExtra(Intent.EXTRA_STREAM, JAVA_URI);
-            try {
-                startActivity(intent);
-                scheduleDelete();
-                mHandled = true;
-                finish();
-                return;
-            } catch (ActivityNotFoundException e) {
-                Slog.i("DumpHeapActivity", "Unable to direct launch to " + directLaunch
-                        + ": " + e.getMessage());
-            }
-        }
-
-        final int messageId;
-        if (isUserInitiated) {
-            messageId = com.android.internal.R.string.dump_heap_ready_text;
-        } else if (isSystemProcess) {
-            messageId = com.android.internal.R.string.dump_heap_system_text;
-        } else {
-            messageId = com.android.internal.R.string.dump_heap_text;
-        }
-        AlertDialog.Builder b = new AlertDialog.Builder(this,
-                android.R.style.Theme_Material_Light_Dialog_Alert);
-        b.setTitle(com.android.internal.R.string.dump_heap_title);
-        b.setMessage(getString(
-                messageId, mProcess, DebugUtils.sizeValueToString(mSize, null)));
-        b.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
-            @Override
-            public void onClick(DialogInterface dialog, int which) {
-                mHandled = true;
-                sendBroadcast(new Intent(ACTION_DELETE_DUMPHEAP));
-                finish();
-            }
-        });
-        b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
-            @Override
-            public void onClick(DialogInterface dialog, int which) {
-                mHandled = true;
-                scheduleDelete();
-                Intent intent = new Intent(Intent.ACTION_SEND);
-                ClipData clip = ClipData.newUri(getContentResolver(), "Heap Dump", JAVA_URI);
-                intent.setClipData(clip);
-                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-                intent.setType(clip.getDescription().getMimeType(0));
-                intent.putExtra(Intent.EXTRA_STREAM, JAVA_URI);
-                startActivity(Intent.createChooser(intent,
-                        getText(com.android.internal.R.string.dump_heap_title)));
-                finish();
-        }
-        });
-        mDialog = b.show();
-    }
-
-    void scheduleDelete() {
-        Intent broadcast = new Intent(ACTION_DELETE_DUMPHEAP);
-        broadcast.putExtra(EXTRA_DELAY_DELETE, true);
-        sendBroadcast(broadcast);
-    }
-
-    @Override
-    protected void onStop() {
-        super.onStop();
-        if (!isChangingConfigurations()) {
-            if (!mHandled) {
-                sendBroadcast(new Intent(ACTION_DELETE_DUMPHEAP));
-            }
-        }
-    }
-
-    @Override
-    protected void onDestroy() {
-        super.onDestroy();
-        mDialog.dismiss();
-    }
-}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 7f18ae3..1beb1c5 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -23,7 +23,6 @@
 import android.annotation.UiThread;
 import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
-import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.app.ActivityThread;
 import android.app.VoiceInteractor.PickOptionRequest;
@@ -35,26 +34,18 @@
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.LabeledIntent;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Insets;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
 import android.net.Uri;
-import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.PatternMatcher;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.StrictMode;
 import android.os.UserHandle;
@@ -71,7 +62,6 @@
 import android.view.WindowInsets;
 import android.widget.AbsListView;
 import android.widget.AdapterView;
-import android.widget.BaseAdapter;
 import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.ListView;
@@ -81,6 +71,8 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.chooser.DisplayResolveInfo;
+import com.android.internal.app.chooser.TargetInfo;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
@@ -99,32 +91,33 @@
  * which to go to.  It is not normally used directly by application developers.
  */
 @UiThread
-public class ResolverActivity extends Activity {
-
-    // Temporary flag for new chooser delegate behavior.
-    boolean mEnableChooserDelegate = true;
+public class ResolverActivity extends Activity implements
+        ResolverListAdapter.ResolverListCommunicator {
 
     @UnsupportedAppUsage
-    protected ResolveListAdapter mAdapter;
+    protected ResolverListAdapter mAdapter;
     private boolean mSafeForwardingMode;
     protected AbsListView mAdapterView;
     private Button mAlwaysButton;
     private Button mOnceButton;
     protected View mProfileView;
-    private int mIconDpi;
     private int mLastSelected = AbsListView.INVALID_POSITION;
     private boolean mResolvingHome = false;
     private int mProfileSwitchMessageId = -1;
     private int mLayoutId;
-    private final ArrayList<Intent> mIntents = new ArrayList<>();
+    @VisibleForTesting
+    protected final ArrayList<Intent> mIntents = new ArrayList<>();
     private PickTargetOptionRequest mPickOptionRequest;
     private String mReferrerPackage;
     private CharSequence mTitle;
     private int mDefaultTitleResId;
-    private boolean mUseLayoutForBrowsables;
+
+    @VisibleForTesting
+    protected boolean mUseLayoutForBrowsables;
 
     // Whether or not this activity supports choosing a default handler for the intent.
-    private boolean mSupportsAlwaysUseOption;
+    @VisibleForTesting
+    protected boolean mSupportsAlwaysUseOption;
     protected ResolverDrawerLayout mResolverDrawerLayout;
     @UnsupportedAppUsage
     protected PackageManager mPm;
@@ -132,12 +125,9 @@
 
     private static final String TAG = "ResolverActivity";
     private static final boolean DEBUG = false;
-    private Runnable mPostListReadyRunnable;
 
     private boolean mRegistered;
 
-    private ColorMatrixColorFilter mSuspendedMatrixColorFilter;
-
     protected Insets mSystemWindowInsets = null;
     private Space mFooterSpacer = null;
 
@@ -150,6 +140,9 @@
 
     private final PackageMonitor mPackageMonitor = createPackageMonitor();
 
+    // Intent extra for connected audio devices
+    public static final String EXTRA_IS_AUDIO_CAPTURE_DEVICE = "is_audio_capture_device";
+
     /**
      * Get the string resource to be used as a label for the link to the resolver activity for an
      * action.
@@ -233,7 +226,7 @@
             @Override
             public void onSomePackagesChanged() {
                 mAdapter.handlePackagesChanged();
-                bindProfileView();
+                updateProfileViewButton();
             }
 
             @Override
@@ -316,9 +309,6 @@
         mRegistered = true;
         mReferrerPackage = getReferrerPackageName();
 
-        final ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
-        mIconDpi = am.getLauncherLargeIconDensity();
-
         // Add our initial intent as the first item, regardless of what else has already been added.
         mIntents.add(0, new Intent(intent));
         mTitle = title;
@@ -330,7 +320,17 @@
 
         mSupportsAlwaysUseOption = supportsAlwaysUseOption;
 
-        if (configureContentView(mIntents, initialIntents, rList)) {
+        // The last argument of createAdapter is whether to do special handling
+        // of the last used choice to highlight it in the list.  We need to always
+        // turn this off when running under voice interaction, since it results in
+        // a more complicated UI that the current voice interaction flow is not able
+        // to handle.
+        boolean filterLastUsed = mSupportsAlwaysUseOption && !isVoiceInteraction();
+        mAdapter = createAdapter(this, mIntents, initialIntents, rList,
+                filterLastUsed, mUseLayoutForBrowsables);
+        configureContentView();
+
+        if (rebuildList()) {
             return;
         }
 
@@ -356,11 +356,9 @@
         mProfileView = findViewById(R.id.profile_button);
         if (mProfileView != null) {
             mProfileView.setOnClickListener(this::onProfileClick);
-            bindProfileView();
+            updateProfileViewButton();
         }
 
-        initSuspendedColorMatrix();
-
         final Set<String> categories = intent.getCategories();
         MetricsLogger.action(this, mAdapter.hasFilteredItem()
                 ? MetricsProto.MetricsEvent.ACTION_SHOW_APP_DISAMBIG_APP_FEATURED
@@ -423,25 +421,7 @@
         }
     }
 
-    private void initSuspendedColorMatrix() {
-        int grayValue = 127;
-        float scale = 0.5f; // half bright
-
-        ColorMatrix tempBrightnessMatrix = new ColorMatrix();
-        float[] mat = tempBrightnessMatrix.getArray();
-        mat[0] = scale;
-        mat[6] = scale;
-        mat[12] = scale;
-        mat[4] = grayValue;
-        mat[9] = grayValue;
-        mat[14] = grayValue;
-
-        ColorMatrix matrix = new ColorMatrix();
-        matrix.setSaturation(0.0f);
-        matrix.preConcat(tempBrightnessMatrix);
-        mSuspendedMatrixColorFilter = new ColorMatrixColorFilter(matrix);
-    }
-
+    @Override // ResolverListCommunicator
     public void sendVoiceChoicesIfNeeded() {
         if (!isVoiceInteraction()) {
             // Clearly not needed.
@@ -476,6 +456,7 @@
         }
     }
 
+    @Override // SelectableTargetInfoCommunicator ResolverListCommunicator
     public Intent getTargetIntent() {
         return mIntents.isEmpty() ? null : mIntents.get(0);
     }
@@ -492,7 +473,8 @@
         return R.layout.resolver_list;
     }
 
-    protected void bindProfileView() {
+    @Override // ResolverListCommunicator
+    public void updateProfileViewButton() {
         if (mProfileView == null) {
             return;
         }
@@ -583,187 +565,6 @@
         }
     }
 
-
-    /**
-     * Loads the icon and label for the provided ApplicationInfo. Defaults to using the application
-     * icon and label over any IntentFilter or Activity icon to increase user understanding, with an
-     * exception for applications that hold the right permission. Always attempts to use available
-     * resources over PackageManager loading mechanisms so badging can be done by iconloader. Uses
-     * Strings to strip creative formatting.
-     */
-    private abstract static class TargetPresentationGetter {
-        @Nullable abstract Drawable getIconSubstituteInternal();
-        @Nullable abstract String getAppSubLabelInternal();
-
-        private Context mCtx;
-        private final int mIconDpi;
-        private final boolean mHasSubstitutePermission;
-        private final ApplicationInfo mAi;
-
-        protected PackageManager mPm;
-
-        TargetPresentationGetter(Context ctx, int iconDpi, ApplicationInfo ai) {
-            mCtx = ctx;
-            mPm = ctx.getPackageManager();
-            mAi = ai;
-            mIconDpi = iconDpi;
-            mHasSubstitutePermission = PackageManager.PERMISSION_GRANTED == mPm.checkPermission(
-                    android.Manifest.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON,
-                    mAi.packageName);
-        }
-
-        public Drawable getIcon(UserHandle userHandle) {
-            return new BitmapDrawable(mCtx.getResources(), getIconBitmap(userHandle));
-        }
-
-        public Bitmap getIconBitmap(UserHandle userHandle) {
-            Drawable dr = null;
-            if (mHasSubstitutePermission) {
-                dr = getIconSubstituteInternal();
-            }
-
-            if (dr == null) {
-                try {
-                    if (mAi.icon != 0) {
-                        dr = loadIconFromResource(mPm.getResourcesForApplication(mAi), mAi.icon);
-                    }
-                } catch (NameNotFoundException ignore) {
-                }
-            }
-
-            // Fall back to ApplicationInfo#loadIcon if nothing has been loaded
-            if (dr == null) {
-                dr = mAi.loadIcon(mPm);
-            }
-
-            SimpleIconFactory sif = SimpleIconFactory.obtain(mCtx);
-            Bitmap icon = sif.createUserBadgedIconBitmap(dr, userHandle);
-            sif.recycle();
-
-            return icon;
-        }
-
-        public String getLabel() {
-            String label = null;
-            // Apps with the substitute permission will always show the sublabel as their label
-            if (mHasSubstitutePermission) {
-                label = getAppSubLabelInternal();
-            }
-
-            if (label == null) {
-                label = (String) mAi.loadLabel(mPm);
-            }
-
-            return label;
-        }
-
-        public String getSubLabel() {
-            // Apps with the substitute permission will never have a sublabel
-            if (mHasSubstitutePermission) return null;
-            return getAppSubLabelInternal();
-        }
-
-        protected String loadLabelFromResource(Resources res, int resId) {
-            return res.getString(resId);
-        }
-
-        @Nullable
-        protected Drawable loadIconFromResource(Resources res, int resId) {
-            return res.getDrawableForDensity(resId, mIconDpi);
-        }
-
-    }
-
-    /**
-     * Loads the icon and label for the provided ResolveInfo.
-     */
-    @VisibleForTesting
-    public static class ResolveInfoPresentationGetter extends ActivityInfoPresentationGetter {
-        private final ResolveInfo mRi;
-        public ResolveInfoPresentationGetter(Context ctx, int iconDpi, ResolveInfo ri) {
-            super(ctx, iconDpi, ri.activityInfo);
-            mRi = ri;
-        }
-
-        @Override
-        Drawable getIconSubstituteInternal() {
-            Drawable dr = null;
-            try {
-                // Do not use ResolveInfo#getIconResource() as it defaults to the app
-                if (mRi.resolvePackageName != null && mRi.icon != 0) {
-                    dr = loadIconFromResource(
-                            mPm.getResourcesForApplication(mRi.resolvePackageName), mRi.icon);
-                }
-            } catch (NameNotFoundException e) {
-                Log.e(TAG, "SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON permission granted but "
-                        + "couldn't find resources for package", e);
-            }
-
-            // Fall back to ActivityInfo if no icon is found via ResolveInfo
-            if (dr == null) dr = super.getIconSubstituteInternal();
-
-            return dr;
-        }
-
-        @Override
-        String getAppSubLabelInternal() {
-            // Will default to app name if no intent filter or activity label set, make sure to
-            // check if subLabel matches label before final display
-            return (String) mRi.loadLabel(mPm);
-        }
-    }
-
-    ResolveInfoPresentationGetter makePresentationGetter(ResolveInfo ri) {
-        return new ResolveInfoPresentationGetter(this, mIconDpi, ri);
-    }
-
-    /**
-     * Loads the icon and label for the provided ActivityInfo.
-     */
-    @VisibleForTesting
-    public static class ActivityInfoPresentationGetter extends TargetPresentationGetter {
-        private final ActivityInfo mActivityInfo;
-        public ActivityInfoPresentationGetter(Context ctx, int iconDpi,
-                ActivityInfo activityInfo) {
-            super(ctx, iconDpi, activityInfo.applicationInfo);
-            mActivityInfo = activityInfo;
-        }
-
-        @Override
-        Drawable getIconSubstituteInternal() {
-            Drawable dr = null;
-            try {
-                // Do not use ActivityInfo#getIconResource() as it defaults to the app
-                if (mActivityInfo.icon != 0) {
-                    dr = loadIconFromResource(
-                            mPm.getResourcesForApplication(mActivityInfo.applicationInfo),
-                            mActivityInfo.icon);
-                }
-            } catch (NameNotFoundException e) {
-                Log.e(TAG, "SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON permission granted but "
-                        + "couldn't find resources for package", e);
-            }
-
-            return dr;
-        }
-
-        @Override
-        String getAppSubLabelInternal() {
-            // Will default to app name if no activity label set, make sure to check if subLabel
-            // matches label before final display
-            return (String) mActivityInfo.loadLabel(mPm);
-        }
-    }
-
-    protected ActivityInfoPresentationGetter makePresentationGetter(ActivityInfo ai) {
-        return new ActivityInfoPresentationGetter(this, mIconDpi, ai);
-    }
-
-    Drawable loadIconForResolveInfo(ResolveInfo ri) {
-        // Load icons based on the current process. If in work profile icons should be badged.
-        return makePresentationGetter(ri).getIcon(Process.myUserHandle());
-    }
-
     @Override
     protected void onRestart() {
         super.onRestart();
@@ -772,7 +573,7 @@
             mRegistered = true;
         }
         mAdapter.handlePackagesChanged();
-        bindProfileView();
+        updateProfileViewButton();
     }
 
     @Override
@@ -804,12 +605,8 @@
         if (!isChangingConfigurations() && mPickOptionRequest != null) {
             mPickOptionRequest.cancel();
         }
-        if (mPostListReadyRunnable != null) {
-            getMainThreadHandler().removeCallbacks(mPostListReadyRunnable);
-            mPostListReadyRunnable = null;
-        }
-        if (mAdapter != null && mAdapter.mResolverListController != null) {
-            mAdapter.mResolverListController.destroy();
+        if (mAdapter != null) {
+            mAdapter.onDestroy();
         }
     }
 
@@ -950,10 +747,30 @@
     /**
      * Replace me in subclasses!
      */
+    @Override // ResolverListCommunicator
     public Intent getReplacementIntent(ActivityInfo aInfo, Intent defIntent) {
         return defIntent;
     }
 
+    @Override // ResolverListCommunicator
+    public void onPostListReady() {
+        setHeader();
+        resetButtonBar();
+        onListRebuilt();
+    }
+
+    protected void onListRebuilt() {
+        int count = mAdapter.getUnfilteredCount();
+        if (count == 1 && mAdapter.getOtherProfile() == null) {
+            // Only one target, so we're a candidate to auto-launch!
+            final TargetInfo target = mAdapter.targetInfoForPosition(0, false);
+            if (shouldAutoLaunchSingleChoice(target)) {
+                safelyStartActivity(target);
+                finish();
+            }
+        }
+    }
+
     protected boolean onTargetSelected(TargetInfo target, boolean alwaysCheck) {
         final ResolveInfo ri = target.getResolveInfo();
         final Intent intent = target != null ? target.getResolvedIntent() : null;
@@ -1049,8 +866,8 @@
                 // If we don't add back in the component for forwarding the intent to a managed
                 // profile, the preferred activity may not be updated correctly (as the set of
                 // components we tell it we knew about will have changed).
-                final boolean needToAddBackProfileForwardingComponent
-                        = mAdapter.mOtherProfile != null;
+                final boolean needToAddBackProfileForwardingComponent =
+                        mAdapter.getOtherProfile() != null;
                 if (!needToAddBackProfileForwardingComponent) {
                     set = new ComponentName[N];
                 } else {
@@ -1066,8 +883,8 @@
                 }
 
                 if (needToAddBackProfileForwardingComponent) {
-                    set[N] = mAdapter.mOtherProfile.getResolvedComponentName();
-                    final int otherProfileMatch = mAdapter.mOtherProfile.getResolveInfo().match;
+                    set[N] = mAdapter.getOtherProfile().getResolvedComponentName();
+                    final int otherProfileMatch = mAdapter.getOtherProfile().getResolveInfo().match;
                     if (otherProfileMatch > bestMatch) bestMatch = otherProfileMatch;
                 }
 
@@ -1169,7 +986,7 @@
     }
 
 
-    boolean startAsCallerImpl(Intent intent, Bundle options, boolean ignoreTargetSecurity,
+    public boolean startAsCallerImpl(Intent intent, Bundle options, boolean ignoreTargetSecurity,
             int userId) {
         // Pass intent to delegate chooser activity with permission token.
         // TODO: This should move to a trampoline Activity in the system when the ChooserActivity
@@ -1205,6 +1022,7 @@
         // Do nothing
     }
 
+    @Override // ResolverListCommunicator
     public boolean shouldGetActivityMetadata() {
         return false;
     }
@@ -1220,11 +1038,17 @@
         startActivity(in);
     }
 
-    public ResolveListAdapter createAdapter(Context context, List<Intent> payloadIntents,
-            Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid,
-            boolean filterLastUsed) {
-        return new ResolveListAdapter(context, payloadIntents, initialIntents, rList,
-                launchedFromUid, filterLastUsed, createListController());
+    public ResolverListAdapter createAdapter(Context context, List<Intent> payloadIntents,
+            Intent[] initialIntents, List<ResolveInfo> rList,
+            boolean filterLastUsed, boolean useLayoutForBrowsables) {
+
+        Intent startIntent = getIntent();
+        boolean isAudioCaptureDevice =
+                startIntent.getBooleanExtra(EXTRA_IS_AUDIO_CAPTURE_DEVICE, false);
+
+        return new ResolverListAdapter(context, payloadIntents, initialIntents, rList,
+                filterLastUsed, createListController(), useLayoutForBrowsables, this,
+                isAudioCaptureDevice);
     }
 
     @VisibleForTesting
@@ -1238,26 +1062,34 @@
     }
 
     /**
-     * Returns true if the activity is finishing and creation should halt
+     * Sets up the content view.
      */
-    public boolean configureContentView(List<Intent> payloadIntents, Intent[] initialIntents,
-            List<ResolveInfo> rList) {
-        // The last argument of createAdapter is whether to do special handling
-        // of the last used choice to highlight it in the list.  We need to always
-        // turn this off when running under voice interaction, since it results in
-        // a more complicated UI that the current voice interaction flow is not able
-        // to handle.
-        mAdapter = createAdapter(this, payloadIntents, initialIntents, rList,
-                mLaunchedFromUid, mSupportsAlwaysUseOption && !isVoiceInteraction());
-        boolean rebuildCompleted = mAdapter.rebuildList();
-
+    private void configureContentView() {
+        if (mAdapter == null) {
+            throw new IllegalStateException("mAdapter cannot be null.");
+        }
         if (useLayoutWithDefault()) {
             mLayoutId = R.layout.resolver_list_with_default;
         } else {
             mLayoutId = getLayoutResource();
         }
         setContentView(mLayoutId);
+        mAdapterView = findViewById(R.id.resolver_list);
+    }
 
+    /**
+     * Returns true if the activity is finishing and creation should halt.
+     * </p>Subclasses must call rebuildListInternal at the end of rebuildList.
+     */
+    protected boolean rebuildList() {
+        return rebuildListInternal();
+    }
+
+    /**
+     * Returns true if the activity is finishing and creation should halt.
+     */
+    final boolean rebuildListInternal() {
+        boolean rebuildCompleted = mAdapter.rebuildList();
         int count = mAdapter.getUnfilteredCount();
 
         // We only rebuild asynchronously when we have multiple elements to sort. In the case where
@@ -1276,10 +1108,7 @@
             }
         }
 
-
-        mAdapterView = findViewById(R.id.resolver_list);
-
-        if (count == 0 && mAdapter.mPlaceholderCount == 0) {
+        if (count == 0 && mAdapter.getPlaceholderCount() == 0) {
             final TextView emptyView = findViewById(R.id.empty);
             emptyView.setVisibility(View.VISIBLE);
             mAdapterView.setVisibility(View.GONE);
@@ -1290,7 +1119,7 @@
         return false;
     }
 
-    public void onPrepareAdapterView(AbsListView adapterView, ResolveListAdapter adapter) {
+    public void onPrepareAdapterView(AbsListView adapterView, ResolverListAdapter adapter) {
         final boolean useHeader = adapter.hasFilteredItem();
         final ListView listView = adapterView instanceof ListView ? (ListView) adapterView : null;
 
@@ -1317,7 +1146,7 @@
      * Configure the area above the app selection list (title, content preview, etc).
      */
     public void setHeader() {
-        if (mAdapter.getCount() == 0 && mAdapter.mPlaceholderCount == 0) {
+        if (mAdapter.getCount() == 0 && mAdapter.getPlaceholderCount() == 0) {
             final TextView titleView = findViewById(R.id.title);
             if (titleView != null) {
                 titleView.setVisibility(View.GONE);
@@ -1337,9 +1166,8 @@
         }
 
         final ImageView iconView = findViewById(R.id.icon);
-        final DisplayResolveInfo iconInfo = mAdapter.getFilteredItem();
-        if (iconView != null && iconInfo != null) {
-            new LoadIconTask(iconInfo, iconView).execute();
+        if (iconView != null) {
+            mAdapter.loadFilteredItemIconTaskAsync(iconView);
         }
     }
 
@@ -1382,7 +1210,8 @@
         }
     }
 
-    private boolean useLayoutWithDefault() {
+    @Override // ResolverListCommunicator
+    public boolean useLayoutWithDefault() {
         return mSupportsAlwaysUseOption && mAdapter.hasFilteredItem();
     }
 
@@ -1397,695 +1226,22 @@
     /**
      * Check a simple match for the component of two ResolveInfos.
      */
-    static boolean resolveInfoMatch(ResolveInfo lhs, ResolveInfo rhs) {
+    @Override // ResolverListCommunicator
+    public boolean resolveInfoMatch(ResolveInfo lhs, ResolveInfo rhs) {
         return lhs == null ? rhs == null
                 : lhs.activityInfo == null ? rhs.activityInfo == null
                 : Objects.equals(lhs.activityInfo.name, rhs.activityInfo.name)
                 && Objects.equals(lhs.activityInfo.packageName, rhs.activityInfo.packageName);
     }
 
-    public final class DisplayResolveInfo implements TargetInfo {
-        private final ResolveInfo mResolveInfo;
-        private final CharSequence mDisplayLabel;
-        private Drawable mDisplayIcon;
-        private Drawable mBadge;
-        private final CharSequence mExtendedInfo;
-        private final Intent mResolvedIntent;
-        private final List<Intent> mSourceIntents = new ArrayList<>();
-        private boolean mIsSuspended;
-
-        public DisplayResolveInfo(Intent originalIntent, ResolveInfo pri, CharSequence pLabel,
-                CharSequence pInfo, Intent pOrigIntent) {
-            mSourceIntents.add(originalIntent);
-            mResolveInfo = pri;
-            mDisplayLabel = pLabel;
-            mExtendedInfo = pInfo;
-
-            final Intent intent = new Intent(pOrigIntent != null ? pOrigIntent :
-                    getReplacementIntent(pri.activityInfo, getTargetIntent()));
-            intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
-                    | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
-            final ActivityInfo ai = mResolveInfo.activityInfo;
-            intent.setComponent(new ComponentName(ai.applicationInfo.packageName, ai.name));
-
-            mIsSuspended = (ai.applicationInfo.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
-
-            mResolvedIntent = intent;
-        }
-
-        private DisplayResolveInfo(DisplayResolveInfo other, Intent fillInIntent, int flags) {
-            mSourceIntents.addAll(other.getAllSourceIntents());
-            mResolveInfo = other.mResolveInfo;
-            mDisplayLabel = other.mDisplayLabel;
-            mDisplayIcon = other.mDisplayIcon;
-            mExtendedInfo = other.mExtendedInfo;
-            mResolvedIntent = new Intent(other.mResolvedIntent);
-            mResolvedIntent.fillIn(fillInIntent, flags);
-        }
-
-        public ResolveInfo getResolveInfo() {
-            return mResolveInfo;
-        }
-
-        public CharSequence getDisplayLabel() {
-            return mDisplayLabel;
-        }
-
-        public Drawable getDisplayIcon() {
-            return mDisplayIcon;
-        }
-
-        @Override
-        public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
-            return new DisplayResolveInfo(this, fillInIntent, flags);
-        }
-
-        @Override
-        public List<Intent> getAllSourceIntents() {
-            return mSourceIntents;
-        }
-
-        public void addAlternateSourceIntent(Intent alt) {
-            mSourceIntents.add(alt);
-        }
-
-        public void setDisplayIcon(Drawable icon) {
-            mDisplayIcon = icon;
-        }
-
-        public boolean hasDisplayIcon() {
-            return mDisplayIcon != null;
-        }
-
-        public CharSequence getExtendedInfo() {
-            return mExtendedInfo;
-        }
-
-        public Intent getResolvedIntent() {
-            return mResolvedIntent;
-        }
-
-        @Override
-        public ComponentName getResolvedComponentName() {
-            return new ComponentName(mResolveInfo.activityInfo.packageName,
-                    mResolveInfo.activityInfo.name);
-        }
-
-        @Override
-        public boolean start(Activity activity, Bundle options) {
-            activity.startActivity(mResolvedIntent, options);
-            return true;
-        }
-
-        @Override
-        public boolean startAsCaller(ResolverActivity activity, Bundle options, int userId) {
-            if (mEnableChooserDelegate) {
-                return activity.startAsCallerImpl(mResolvedIntent, options, false, userId);
-            } else {
-                activity.startActivityAsCaller(mResolvedIntent, options, null, false, userId);
-                return true;
-            }
-        }
-
-        @Override
-        public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
-            activity.startActivityAsUser(mResolvedIntent, options, user);
-            return false;
-        }
-
-        public boolean isSuspended() {
-            return mIsSuspended;
+    @Override // ResolverListCommunicator
+    public void onHandlePackagesChanged() {
+        if (mAdapter.getCount() == 0) {
+            // We no longer have any items...  just finish the activity.
+            finish();
         }
     }
 
-    List<DisplayResolveInfo> getDisplayList() {
-        return mAdapter.mDisplayList;
-    }
-
-    /**
-     * A single target as represented in the chooser.
-     */
-    public interface TargetInfo {
-        /**
-         * Get the resolved intent that represents this target. Note that this may not be the
-         * intent that will be launched by calling one of the <code>start</code> methods provided;
-         * this is the intent that will be credited with the launch.
-         *
-         * @return the resolved intent for this target
-         */
-        Intent getResolvedIntent();
-
-        /**
-         * Get the resolved component name that represents this target. Note that this may not
-         * be the component that will be directly launched by calling one of the <code>start</code>
-         * methods provided; this is the component that will be credited with the launch.
-         *
-         * @return the resolved ComponentName for this target
-         */
-        ComponentName getResolvedComponentName();
-
-        /**
-         * Start the activity referenced by this target.
-         *
-         * @param activity calling Activity performing the launch
-         * @param options ActivityOptions bundle
-         * @return true if the start completed successfully
-         */
-        boolean start(Activity activity, Bundle options);
-
-        /**
-         * Start the activity referenced by this target as if the ResolverActivity's caller
-         * was performing the start operation.
-         *
-         * @param activity calling Activity (actually) performing the launch
-         * @param options ActivityOptions bundle
-         * @param userId userId to start as or {@link UserHandle#USER_NULL} for activity's caller
-         * @return true if the start completed successfully
-         */
-        boolean startAsCaller(ResolverActivity activity, Bundle options, int userId);
-
-        /**
-         * Start the activity referenced by this target as a given user.
-         *
-         * @param activity calling activity performing the launch
-         * @param options ActivityOptions bundle
-         * @param user handle for the user to start the activity as
-         * @return true if the start completed successfully
-         */
-        boolean startAsUser(Activity activity, Bundle options, UserHandle user);
-
-        /**
-         * Return the ResolveInfo about how and why this target matched the original query
-         * for available targets.
-         *
-         * @return ResolveInfo representing this target's match
-         */
-        ResolveInfo getResolveInfo();
-
-        /**
-         * Return the human-readable text label for this target.
-         *
-         * @return user-visible target label
-         */
-        CharSequence getDisplayLabel();
-
-        /**
-         * Return any extended info for this target. This may be used to disambiguate
-         * otherwise identical targets.
-         *
-         * @return human-readable disambig string or null if none present
-         */
-        CharSequence getExtendedInfo();
-
-        /**
-         * @return The drawable that should be used to represent this target including badge
-         */
-        Drawable getDisplayIcon();
-
-        /**
-         * Clone this target with the given fill-in information.
-         */
-        TargetInfo cloneFilledIn(Intent fillInIntent, int flags);
-
-        /**
-         * @return the list of supported source intents deduped against this single target
-         */
-        List<Intent> getAllSourceIntents();
-
-        /**
-          * @return true if this target can be selected by the user
-          */
-        boolean isSuspended();
-    }
-
-    public class ResolveListAdapter extends BaseAdapter {
-        private final List<Intent> mIntents;
-        private final Intent[] mInitialIntents;
-        private final List<ResolveInfo> mBaseResolveList;
-        protected ResolveInfo mLastChosen;
-        private DisplayResolveInfo mOtherProfile;
-        ResolverListController mResolverListController;
-        private int mPlaceholderCount;
-        private boolean mAllTargetsAreBrowsers = false;
-
-        protected final LayoutInflater mInflater;
-
-        // This one is the list that the Adapter will actually present.
-        List<DisplayResolveInfo> mDisplayList;
-        List<ResolvedComponentInfo> mUnfilteredResolveList;
-
-        private int mLastChosenPosition = -1;
-        private boolean mFilterLastUsed;
-
-        public ResolveListAdapter(Context context, List<Intent> payloadIntents,
-                Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid,
-                boolean filterLastUsed,
-                ResolverListController resolverListController) {
-            mIntents = payloadIntents;
-            mInitialIntents = initialIntents;
-            mBaseResolveList = rList;
-            mLaunchedFromUid = launchedFromUid;
-            mInflater = LayoutInflater.from(context);
-            mDisplayList = new ArrayList<>();
-            mFilterLastUsed = filterLastUsed;
-            mResolverListController = resolverListController;
-        }
-
-        public void handlePackagesChanged() {
-            rebuildList();
-            if (getCount() == 0) {
-                // We no longer have any items...  just finish the activity.
-                finish();
-            }
-        }
-
-        public void setPlaceholderCount(int count) {
-            mPlaceholderCount = count;
-        }
-
-        public int getPlaceholderCount() { return mPlaceholderCount; }
-
-        @Nullable
-        public DisplayResolveInfo getFilteredItem() {
-            if (mFilterLastUsed && mLastChosenPosition >= 0) {
-                // Not using getItem since it offsets to dodge this position for the list
-                return mDisplayList.get(mLastChosenPosition);
-            }
-            return null;
-        }
-
-        public DisplayResolveInfo getOtherProfile() {
-            return mOtherProfile;
-        }
-
-        public int getFilteredPosition() {
-            if (mFilterLastUsed && mLastChosenPosition >= 0) {
-                return mLastChosenPosition;
-            }
-            return AbsListView.INVALID_POSITION;
-        }
-
-        public boolean hasFilteredItem() {
-            return mFilterLastUsed && mLastChosen != null;
-        }
-
-        public float getScore(DisplayResolveInfo target) {
-            return mResolverListController.getScore(target);
-        }
-
-        public void updateModel(ComponentName componentName) {
-            mResolverListController.updateModel(componentName);
-        }
-
-        public void updateChooserCounts(String packageName, int userId, String action) {
-            mResolverListController.updateChooserCounts(packageName, userId, action);
-        }
-
-        /**
-          * @return true if all items in the display list are defined as browsers by
-          *         ResolveInfo.handleAllWebDataURI
-          */
-        public boolean areAllTargetsBrowsers() {
-            return mAllTargetsAreBrowsers;
-        }
-
-        /**
-         * Rebuild the list of resolvers. In some cases some parts will need some asynchronous work
-         * to complete.
-         *
-         * @return Whether or not the list building is completed.
-         */
-        protected boolean rebuildList() {
-            List<ResolvedComponentInfo> currentResolveList = null;
-            // Clear the value of mOtherProfile from previous call.
-            mOtherProfile = null;
-            mLastChosen = null;
-            mLastChosenPosition = -1;
-            mAllTargetsAreBrowsers = false;
-            mDisplayList.clear();
-            if (mBaseResolveList != null) {
-                currentResolveList = mUnfilteredResolveList = new ArrayList<>();
-                mResolverListController.addResolveListDedupe(currentResolveList,
-                        getTargetIntent(),
-                        mBaseResolveList);
-            } else {
-                currentResolveList = mUnfilteredResolveList =
-                        mResolverListController.getResolversForIntent(shouldGetResolvedFilter(),
-                                shouldGetActivityMetadata(),
-                                mIntents);
-                if (currentResolveList == null) {
-                    processSortedList(currentResolveList);
-                    return true;
-                }
-                List<ResolvedComponentInfo> originalList =
-                        mResolverListController.filterIneligibleActivities(currentResolveList,
-                                true);
-                if (originalList != null) {
-                    mUnfilteredResolveList = originalList;
-                }
-            }
-
-            // So far we only support a single other profile at a time.
-            // The first one we see gets special treatment.
-            for (ResolvedComponentInfo info : currentResolveList) {
-                if (info.getResolveInfoAt(0).targetUserId != UserHandle.USER_CURRENT) {
-                    mOtherProfile = new DisplayResolveInfo(info.getIntentAt(0),
-                            info.getResolveInfoAt(0),
-                            info.getResolveInfoAt(0).loadLabel(mPm),
-                            info.getResolveInfoAt(0).loadLabel(mPm),
-                            getReplacementIntent(info.getResolveInfoAt(0).activityInfo,
-                                    info.getIntentAt(0)));
-                    currentResolveList.remove(info);
-                    break;
-                }
-            }
-
-            if (mOtherProfile == null) {
-                try {
-                    mLastChosen = mResolverListController.getLastChosen();
-                } catch (RemoteException re) {
-                    Log.d(TAG, "Error calling getLastChosenActivity\n" + re);
-                }
-            }
-
-            int N;
-            if ((currentResolveList != null) && ((N = currentResolveList.size()) > 0)) {
-                // We only care about fixing the unfilteredList if the current resolve list and
-                // current resolve list are currently the same.
-                List<ResolvedComponentInfo> originalList =
-                        mResolverListController.filterLowPriority(currentResolveList,
-                                mUnfilteredResolveList == currentResolveList);
-                if (originalList != null) {
-                    mUnfilteredResolveList = originalList;
-                }
-
-                if (currentResolveList.size() > 1) {
-                    int placeholderCount = currentResolveList.size();
-                    if (useLayoutWithDefault()) {
-                        --placeholderCount;
-                    }
-                    setPlaceholderCount(placeholderCount);
-                    createSortingTask().execute(currentResolveList);
-                    postListReadyRunnable();
-                    return false;
-                } else {
-                    processSortedList(currentResolveList);
-                    return true;
-                }
-            } else {
-                processSortedList(currentResolveList);
-                return true;
-            }
-        }
-
-        AsyncTask<List<ResolvedComponentInfo>,
-                Void,
-                List<ResolvedComponentInfo>> createSortingTask() {
-            return new AsyncTask<List<ResolvedComponentInfo>,
-                    Void,
-                    List<ResolvedComponentInfo>>() {
-                @Override
-                protected List<ResolvedComponentInfo> doInBackground(
-                        List<ResolvedComponentInfo>... params) {
-                    mResolverListController.sort(params[0]);
-                    return params[0];
-                }
-
-                @Override
-                protected void onPostExecute(List<ResolvedComponentInfo> sortedComponents) {
-                    processSortedList(sortedComponents);
-                    bindProfileView();
-                    notifyDataSetChanged();
-                }
-            };
-        }
-
-        void processSortedList(List<ResolvedComponentInfo> sortedComponents) {
-            int N;
-            if (sortedComponents != null && (N = sortedComponents.size()) != 0) {
-                mAllTargetsAreBrowsers = mUseLayoutForBrowsables;
-
-                // First put the initial items at the top.
-                if (mInitialIntents != null) {
-                    for (int i = 0; i < mInitialIntents.length; i++) {
-                        Intent ii = mInitialIntents[i];
-                        if (ii == null) {
-                            continue;
-                        }
-                        ActivityInfo ai = ii.resolveActivityInfo(
-                                getPackageManager(), 0);
-                        if (ai == null) {
-                            Log.w(TAG, "No activity found for " + ii);
-                            continue;
-                        }
-                        ResolveInfo ri = new ResolveInfo();
-                        ri.activityInfo = ai;
-                        UserManager userManager =
-                                (UserManager) getSystemService(Context.USER_SERVICE);
-                        if (ii instanceof LabeledIntent) {
-                            LabeledIntent li = (LabeledIntent) ii;
-                            ri.resolvePackageName = li.getSourcePackage();
-                            ri.labelRes = li.getLabelResource();
-                            ri.nonLocalizedLabel = li.getNonLocalizedLabel();
-                            ri.icon = li.getIconResource();
-                            ri.iconResourceId = ri.icon;
-                        }
-                        if (userManager.isManagedProfile()) {
-                            ri.noResourceId = true;
-                            ri.icon = 0;
-                        }
-                        mAllTargetsAreBrowsers &= ri.handleAllWebDataURI;
-
-                        addResolveInfo(new DisplayResolveInfo(ii, ri,
-                                ri.loadLabel(getPackageManager()), null, ii));
-                    }
-                }
-
-
-                for (ResolvedComponentInfo rci : sortedComponents) {
-                    final ResolveInfo ri = rci.getResolveInfoAt(0);
-                    if (ri != null) {
-                        mAllTargetsAreBrowsers &= ri.handleAllWebDataURI;
-
-                        ResolveInfoPresentationGetter pg = makePresentationGetter(ri);
-                        addResolveInfoWithAlternates(rci, pg.getSubLabel(), pg.getLabel());
-                    }
-                }
-            }
-
-            sendVoiceChoicesIfNeeded();
-            postListReadyRunnable();
-        }
-
-
-
-        /**
-         * Some necessary methods for creating the list are initiated in onCreate and will also
-         * determine the layout known. We therefore can't update the UI inline and post to the
-         * handler thread to update after the current task is finished.
-         */
-        private void postListReadyRunnable() {
-            if (mPostListReadyRunnable == null) {
-                mPostListReadyRunnable = new Runnable() {
-                    @Override
-                    public void run() {
-                        setHeader();
-                        resetButtonBar();
-                        onListRebuilt();
-                        mPostListReadyRunnable = null;
-                    }
-                };
-                getMainThreadHandler().post(mPostListReadyRunnable);
-            }
-        }
-
-        public void onListRebuilt() {
-            int count = getUnfilteredCount();
-            if (count == 1 && getOtherProfile() == null) {
-                // Only one target, so we're a candidate to auto-launch!
-                final TargetInfo target = targetInfoForPosition(0, false);
-                if (shouldAutoLaunchSingleChoice(target)) {
-                    safelyStartActivity(target);
-                    finish();
-                }
-            }
-        }
-
-        public boolean shouldGetResolvedFilter() {
-            return mFilterLastUsed;
-        }
-
-        private void addResolveInfoWithAlternates(ResolvedComponentInfo rci,
-                CharSequence extraInfo, CharSequence roLabel) {
-            final int count = rci.getCount();
-            final Intent intent = rci.getIntentAt(0);
-            final ResolveInfo add = rci.getResolveInfoAt(0);
-            final Intent replaceIntent = getReplacementIntent(add.activityInfo, intent);
-            final DisplayResolveInfo dri = new DisplayResolveInfo(intent, add, roLabel,
-                    extraInfo, replaceIntent);
-            addResolveInfo(dri);
-            if (replaceIntent == intent) {
-                // Only add alternates if we didn't get a specific replacement from
-                // the caller. If we have one it trumps potential alternates.
-                for (int i = 1, N = count; i < N; i++) {
-                    final Intent altIntent = rci.getIntentAt(i);
-                    dri.addAlternateSourceIntent(altIntent);
-                }
-            }
-            updateLastChosenPosition(add);
-        }
-
-        private void updateLastChosenPosition(ResolveInfo info) {
-            // If another profile is present, ignore the last chosen entry.
-            if (mOtherProfile != null) {
-                mLastChosenPosition = -1;
-                return;
-            }
-            if (mLastChosen != null
-                    && mLastChosen.activityInfo.packageName.equals(info.activityInfo.packageName)
-                    && mLastChosen.activityInfo.name.equals(info.activityInfo.name)) {
-                mLastChosenPosition = mDisplayList.size() - 1;
-            }
-        }
-
-        // We assume that at this point we've already filtered out the only intent for a different
-        // targetUserId which we're going to use.
-        private void addResolveInfo(DisplayResolveInfo dri) {
-            if (dri != null && dri.mResolveInfo != null
-                    && dri.mResolveInfo.targetUserId == UserHandle.USER_CURRENT) {
-                // Checks if this info is already listed in display.
-                for (DisplayResolveInfo existingInfo : mDisplayList) {
-                    if (resolveInfoMatch(dri.mResolveInfo, existingInfo.mResolveInfo)) {
-                        return;
-                    }
-                }
-                mDisplayList.add(dri);
-            }
-        }
-
-        @Nullable
-        public ResolveInfo resolveInfoForPosition(int position, boolean filtered) {
-            TargetInfo target = targetInfoForPosition(position, filtered);
-            if (target != null) {
-                return target.getResolveInfo();
-             }
-             return null;
-        }
-
-        @Nullable
-        public TargetInfo targetInfoForPosition(int position, boolean filtered) {
-            if (filtered) {
-                return getItem(position);
-            }
-            if (mDisplayList.size() > position) {
-                return mDisplayList.get(position);
-            }
-            return null;
-        }
-
-        public int getCount() {
-            int totalSize = mDisplayList == null || mDisplayList.isEmpty() ? mPlaceholderCount :
-                    mDisplayList.size();
-            if (mFilterLastUsed && mLastChosenPosition >= 0) {
-                totalSize--;
-            }
-            return totalSize;
-        }
-
-        public int getUnfilteredCount() {
-            return mDisplayList.size();
-        }
-
-        @Nullable
-        public TargetInfo getItem(int position) {
-            if (mFilterLastUsed && mLastChosenPosition >= 0 && position >= mLastChosenPosition) {
-                position++;
-            }
-            if (mDisplayList.size() > position) {
-                return mDisplayList.get(position);
-            } else {
-                return null;
-            }
-        }
-
-        public long getItemId(int position) {
-            return position;
-        }
-
-        public int getDisplayResolveInfoCount() {
-            return mDisplayList.size();
-        }
-
-        public DisplayResolveInfo getDisplayResolveInfo(int index) {
-            // Used to query services. We only query services for primary targets, not alternates.
-            return mDisplayList.get(index);
-        }
-
-        public final View getView(int position, View convertView, ViewGroup parent) {
-            View view = convertView;
-            if (view == null) {
-                view = createView(parent);
-            }
-            onBindView(view, getItem(position));
-            return view;
-        }
-
-        public final View createView(ViewGroup parent) {
-            final View view = onCreateView(parent);
-            final ViewHolder holder = new ViewHolder(view);
-            view.setTag(holder);
-            return view;
-        }
-
-        public View onCreateView(ViewGroup parent) {
-            return mInflater.inflate(
-                    com.android.internal.R.layout.resolve_list_item, parent, false);
-        }
-
-        public final void bindView(int position, View view) {
-            onBindView(view, getItem(position));
-        }
-
-        protected void onBindView(View view, TargetInfo info) {
-            final ViewHolder holder = (ViewHolder) view.getTag();
-            if (info == null) {
-                holder.icon.setImageDrawable(
-                        getDrawable(R.drawable.resolver_icon_placeholder));
-                return;
-            }
-
-            final CharSequence label = info.getDisplayLabel();
-            if (!TextUtils.equals(holder.text.getText(), label)) {
-                holder.text.setText(info.getDisplayLabel());
-            }
-
-            // Always show a subLabel for visual consistency across list items. Show an empty
-            // subLabel if the subLabel is the same as the label
-            CharSequence subLabel = info.getExtendedInfo();
-            if (TextUtils.equals(label, subLabel)) subLabel = null;
-
-            if (!TextUtils.equals(holder.text2.getText(), subLabel)
-                    && !TextUtils.isEmpty(subLabel)) {
-                holder.text2.setVisibility(View.VISIBLE);
-                holder.text2.setText(subLabel);
-            }
-
-            if (info.isSuspended()) {
-                holder.icon.setColorFilter(mSuspendedMatrixColorFilter);
-            } else {
-                holder.icon.setColorFilter(null);
-            }
-
-            if (info instanceof DisplayResolveInfo
-                    && !((DisplayResolveInfo) info).hasDisplayIcon()) {
-                new LoadIconTask((DisplayResolveInfo) info, holder.icon).execute();
-            } else {
-                holder.icon.setImageDrawable(info.getDisplayIcon());
-            }
-        }
-    }
-
-
     @VisibleForTesting
     public static final class ResolvedComponentInfo {
         public final ComponentName name;
@@ -2133,23 +1289,6 @@
         }
     }
 
-    static class ViewHolder {
-        public View itemView;
-        public Drawable defaultItemViewBackground;
-
-        public TextView text;
-        public TextView text2;
-        public ImageView icon;
-
-        public ViewHolder(View view) {
-            itemView = view;
-            defaultItemViewBackground = view.getBackground();
-            text = (TextView) view.findViewById(com.android.internal.R.id.text1);
-            text2 = (TextView) view.findViewById(com.android.internal.R.id.text2);
-            icon = (ImageView) view.findViewById(R.id.icon);
-        }
-    }
-
     class ItemClickListener implements AdapterView.OnItemClickListener,
             AdapterView.OnItemLongClickListener {
         @Override
@@ -2200,33 +1339,6 @@
 
     }
 
-    class LoadIconTask extends AsyncTask<Void, Void, Drawable> {
-        protected final DisplayResolveInfo mDisplayResolveInfo;
-        private final ResolveInfo mResolveInfo;
-        private final ImageView mTargetView;
-
-        LoadIconTask(DisplayResolveInfo dri, ImageView target) {
-            mDisplayResolveInfo = dri;
-            mResolveInfo = dri.getResolveInfo();
-            mTargetView = target;
-        }
-
-        @Override
-        protected Drawable doInBackground(Void... params) {
-            return loadIconForResolveInfo(mResolveInfo);
-        }
-
-        @Override
-        protected void onPostExecute(Drawable d) {
-            if (mAdapter.getOtherProfile() == mDisplayResolveInfo) {
-                bindProfileView();
-            } else {
-                mDisplayResolveInfo.setDisplayIcon(d);
-                mTargetView.setImageDrawable(d);
-            }
-        }
-    }
-
     static final boolean isSpecificUriMatch(int match) {
         match = match&IntentFilter.MATCH_CATEGORY_MASK;
         return match >= IntentFilter.MATCH_CATEGORY_HOST
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
new file mode 100644
index 0000000..a587936
--- /dev/null
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -0,0 +1,889 @@
+/*
+ * 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.internal.app;
+
+import static android.content.Context.ACTIVITY_SERVICE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.PermissionChecker;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.LabeledIntent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
+import com.android.internal.app.chooser.DisplayResolveInfo;
+import com.android.internal.app.chooser.TargetInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ResolverListAdapter extends BaseAdapter {
+    private static final String TAG = "ResolverListAdapter";
+
+    private final List<Intent> mIntents;
+    private final Intent[] mInitialIntents;
+    private final List<ResolveInfo> mBaseResolveList;
+    private final PackageManager mPm;
+    protected final Context mContext;
+    private final ColorMatrixColorFilter mSuspendedMatrixColorFilter;
+    private final boolean mUseLayoutForBrowsables;
+    private final int mIconDpi;
+    protected ResolveInfo mLastChosen;
+    private DisplayResolveInfo mOtherProfile;
+    ResolverListController mResolverListController;
+    private int mPlaceholderCount;
+    private boolean mAllTargetsAreBrowsers = false;
+
+    protected final LayoutInflater mInflater;
+
+    // This one is the list that the Adapter will actually present.
+    List<DisplayResolveInfo> mDisplayList;
+    List<ResolvedComponentInfo> mUnfilteredResolveList;
+
+    private int mLastChosenPosition = -1;
+    private boolean mFilterLastUsed;
+    private final ResolverListCommunicator mResolverListCommunicator;
+    private Runnable mPostListReadyRunnable;
+    private final boolean mIsAudioCaptureDevice;
+
+    public ResolverListAdapter(Context context, List<Intent> payloadIntents,
+            Intent[] initialIntents, List<ResolveInfo> rList,
+            boolean filterLastUsed,
+            ResolverListController resolverListController,
+            boolean useLayoutForBrowsables,
+            ResolverListCommunicator resolverListCommunicator,
+            boolean isAudioCaptureDevice) {
+        mContext = context;
+        mIntents = payloadIntents;
+        mInitialIntents = initialIntents;
+        mBaseResolveList = rList;
+        mInflater = LayoutInflater.from(context);
+        mPm = context.getPackageManager();
+        mDisplayList = new ArrayList<>();
+        mFilterLastUsed = filterLastUsed;
+        mResolverListController = resolverListController;
+        mSuspendedMatrixColorFilter = createSuspendedColorMatrix();
+        mUseLayoutForBrowsables = useLayoutForBrowsables;
+        mResolverListCommunicator = resolverListCommunicator;
+        mIsAudioCaptureDevice = isAudioCaptureDevice;
+        final ActivityManager am = (ActivityManager) mContext.getSystemService(ACTIVITY_SERVICE);
+        mIconDpi = am.getLauncherLargeIconDensity();
+    }
+
+    public void handlePackagesChanged() {
+        rebuildList();
+        mResolverListCommunicator.onHandlePackagesChanged();
+    }
+
+    public void setPlaceholderCount(int count) {
+        mPlaceholderCount = count;
+    }
+
+    public int getPlaceholderCount() {
+        return mPlaceholderCount;
+    }
+
+    @Nullable
+    public DisplayResolveInfo getFilteredItem() {
+        if (mFilterLastUsed && mLastChosenPosition >= 0) {
+            // Not using getItem since it offsets to dodge this position for the list
+            return mDisplayList.get(mLastChosenPosition);
+        }
+        return null;
+    }
+
+    public DisplayResolveInfo getOtherProfile() {
+        return mOtherProfile;
+    }
+
+    public int getFilteredPosition() {
+        if (mFilterLastUsed && mLastChosenPosition >= 0) {
+            return mLastChosenPosition;
+        }
+        return AbsListView.INVALID_POSITION;
+    }
+
+    public boolean hasFilteredItem() {
+        return mFilterLastUsed && mLastChosen != null;
+    }
+
+    public float getScore(DisplayResolveInfo target) {
+        return mResolverListController.getScore(target);
+    }
+
+    public void updateModel(ComponentName componentName) {
+        mResolverListController.updateModel(componentName);
+    }
+
+    public void updateChooserCounts(String packageName, int userId, String action) {
+        mResolverListController.updateChooserCounts(packageName, userId, action);
+    }
+
+    /**
+     * @return true if all items in the display list are defined as browsers by
+     *         ResolveInfo.handleAllWebDataURI
+     */
+    public boolean areAllTargetsBrowsers() {
+        return mAllTargetsAreBrowsers;
+    }
+
+    /**
+     * Rebuild the list of resolvers. In some cases some parts will need some asynchronous work
+     * to complete.
+     *
+     * @return Whether or not the list building is completed.
+     */
+    protected boolean rebuildList() {
+        List<ResolvedComponentInfo> currentResolveList = null;
+        // Clear the value of mOtherProfile from previous call.
+        mOtherProfile = null;
+        mLastChosen = null;
+        mLastChosenPosition = -1;
+        mAllTargetsAreBrowsers = false;
+        mDisplayList.clear();
+        if (mBaseResolveList != null) {
+            currentResolveList = mUnfilteredResolveList = new ArrayList<>();
+            mResolverListController.addResolveListDedupe(currentResolveList,
+                    mResolverListCommunicator.getTargetIntent(),
+                    mBaseResolveList);
+        } else {
+            currentResolveList = mUnfilteredResolveList =
+                    mResolverListController.getResolversForIntent(shouldGetResolvedFilter(),
+                            mResolverListCommunicator.shouldGetActivityMetadata(),
+                            mIntents);
+            if (currentResolveList == null) {
+                processSortedList(currentResolveList);
+                return true;
+            }
+            List<ResolvedComponentInfo> originalList =
+                    mResolverListController.filterIneligibleActivities(currentResolveList,
+                            true);
+            if (originalList != null) {
+                mUnfilteredResolveList = originalList;
+            }
+        }
+
+        // So far we only support a single other profile at a time.
+        // The first one we see gets special treatment.
+        for (ResolvedComponentInfo info : currentResolveList) {
+            ResolveInfo resolveInfo = info.getResolveInfoAt(0);
+            if (resolveInfo.targetUserId != UserHandle.USER_CURRENT) {
+                Intent pOrigIntent = mResolverListCommunicator.getReplacementIntent(
+                        resolveInfo.activityInfo,
+                        info.getIntentAt(0));
+                Intent replacementIntent = mResolverListCommunicator.getReplacementIntent(
+                        resolveInfo.activityInfo,
+                        mResolverListCommunicator.getTargetIntent());
+                mOtherProfile = new DisplayResolveInfo(info.getIntentAt(0),
+                        resolveInfo,
+                        resolveInfo.loadLabel(mPm),
+                        resolveInfo.loadLabel(mPm),
+                        pOrigIntent != null ? pOrigIntent : replacementIntent,
+                        makePresentationGetter(resolveInfo));
+                currentResolveList.remove(info);
+                break;
+            }
+        }
+
+        if (mOtherProfile == null) {
+            try {
+                mLastChosen = mResolverListController.getLastChosen();
+            } catch (RemoteException re) {
+                Log.d(TAG, "Error calling getLastChosenActivity\n" + re);
+            }
+        }
+
+        int n;
+        if ((currentResolveList != null) && ((n = currentResolveList.size()) > 0)) {
+            // We only care about fixing the unfilteredList if the current resolve list and
+            // current resolve list are currently the same.
+            List<ResolvedComponentInfo> originalList =
+                    mResolverListController.filterLowPriority(currentResolveList,
+                            mUnfilteredResolveList == currentResolveList);
+            if (originalList != null) {
+                mUnfilteredResolveList = originalList;
+            }
+
+            if (currentResolveList.size() > 1) {
+                int placeholderCount = currentResolveList.size();
+                if (mResolverListCommunicator.useLayoutWithDefault()) {
+                    --placeholderCount;
+                }
+                setPlaceholderCount(placeholderCount);
+                createSortingTask().execute(currentResolveList);
+                postListReadyRunnable();
+                return false;
+            } else {
+                processSortedList(currentResolveList);
+                return true;
+            }
+        } else {
+            processSortedList(currentResolveList);
+            return true;
+        }
+    }
+
+    AsyncTask<List<ResolvedComponentInfo>,
+            Void,
+            List<ResolvedComponentInfo>> createSortingTask() {
+        return new AsyncTask<List<ResolvedComponentInfo>,
+                Void,
+                List<ResolvedComponentInfo>>() {
+            @Override
+            protected List<ResolvedComponentInfo> doInBackground(
+                    List<ResolvedComponentInfo>... params) {
+                mResolverListController.sort(params[0]);
+                return params[0];
+            }
+            @Override
+            protected void onPostExecute(List<ResolvedComponentInfo> sortedComponents) {
+                processSortedList(sortedComponents);
+                mResolverListCommunicator.updateProfileViewButton();
+                notifyDataSetChanged();
+            }
+        };
+    }
+
+
+    protected void processSortedList(List<ResolvedComponentInfo> sortedComponents) {
+        int n;
+        if (sortedComponents != null && (n = sortedComponents.size()) != 0) {
+            mAllTargetsAreBrowsers = mUseLayoutForBrowsables;
+
+            // First put the initial items at the top.
+            if (mInitialIntents != null) {
+                for (int i = 0; i < mInitialIntents.length; i++) {
+                    Intent ii = mInitialIntents[i];
+                    if (ii == null) {
+                        continue;
+                    }
+                    ActivityInfo ai = ii.resolveActivityInfo(
+                            mPm, 0);
+                    if (ai == null) {
+                        Log.w(TAG, "No activity found for " + ii);
+                        continue;
+                    }
+                    ResolveInfo ri = new ResolveInfo();
+                    ri.activityInfo = ai;
+                    UserManager userManager =
+                            (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+                    if (ii instanceof LabeledIntent) {
+                        LabeledIntent li = (LabeledIntent) ii;
+                        ri.resolvePackageName = li.getSourcePackage();
+                        ri.labelRes = li.getLabelResource();
+                        ri.nonLocalizedLabel = li.getNonLocalizedLabel();
+                        ri.icon = li.getIconResource();
+                        ri.iconResourceId = ri.icon;
+                    }
+                    if (userManager.isManagedProfile()) {
+                        ri.noResourceId = true;
+                        ri.icon = 0;
+                    }
+                    mAllTargetsAreBrowsers &= ri.handleAllWebDataURI;
+
+                    addResolveInfo(new DisplayResolveInfo(ii, ri,
+                            ri.loadLabel(mPm), null, ii, makePresentationGetter(ri)));
+                }
+            }
+
+
+            for (ResolvedComponentInfo rci : sortedComponents) {
+                final ResolveInfo ri = rci.getResolveInfoAt(0);
+                if (ri != null) {
+                    mAllTargetsAreBrowsers &= ri.handleAllWebDataURI;
+                    addResolveInfoWithAlternates(rci);
+                }
+            }
+        }
+
+        mResolverListCommunicator.sendVoiceChoicesIfNeeded();
+        postListReadyRunnable();
+    }
+
+    /**
+     * Some necessary methods for creating the list are initiated in onCreate and will also
+     * determine the layout known. We therefore can't update the UI inline and post to the
+     * handler thread to update after the current task is finished.
+     */
+    private void postListReadyRunnable() {
+        if (mPostListReadyRunnable == null) {
+            mPostListReadyRunnable = new Runnable() {
+                @Override
+                public void run() {
+                    mResolverListCommunicator.onPostListReady();
+                    mPostListReadyRunnable = null;
+                }
+            };
+            mContext.getMainThreadHandler().post(mPostListReadyRunnable);
+        }
+    }
+
+    public boolean shouldGetResolvedFilter() {
+        return mFilterLastUsed;
+    }
+
+    private void addResolveInfoWithAlternates(ResolvedComponentInfo rci) {
+        final int count = rci.getCount();
+        final Intent intent = rci.getIntentAt(0);
+        final ResolveInfo add = rci.getResolveInfoAt(0);
+        final Intent replaceIntent =
+                mResolverListCommunicator.getReplacementIntent(add.activityInfo, intent);
+        final Intent defaultIntent = mResolverListCommunicator.getReplacementIntent(
+                add.activityInfo, mResolverListCommunicator.getTargetIntent());
+        final DisplayResolveInfo
+                dri = new DisplayResolveInfo(intent, add,
+                replaceIntent != null ? replaceIntent : defaultIntent, makePresentationGetter(add));
+        addResolveInfo(dri);
+        if (replaceIntent == intent) {
+            // Only add alternates if we didn't get a specific replacement from
+            // the caller. If we have one it trumps potential alternates.
+            for (int i = 1, n = count; i < n; i++) {
+                final Intent altIntent = rci.getIntentAt(i);
+                dri.addAlternateSourceIntent(altIntent);
+            }
+        }
+        updateLastChosenPosition(add);
+    }
+
+    private void updateLastChosenPosition(ResolveInfo info) {
+        // If another profile is present, ignore the last chosen entry.
+        if (mOtherProfile != null) {
+            mLastChosenPosition = -1;
+            return;
+        }
+        if (mLastChosen != null
+                && mLastChosen.activityInfo.packageName.equals(info.activityInfo.packageName)
+                && mLastChosen.activityInfo.name.equals(info.activityInfo.name)) {
+            mLastChosenPosition = mDisplayList.size() - 1;
+        }
+    }
+
+    // We assume that at this point we've already filtered out the only intent for a different
+    // targetUserId which we're going to use.
+    private void addResolveInfo(DisplayResolveInfo dri) {
+        if (dri != null && dri.getResolveInfo() != null
+                && dri.getResolveInfo().targetUserId == UserHandle.USER_CURRENT) {
+            // Checks if this info is already listed in display.
+            for (DisplayResolveInfo existingInfo : mDisplayList) {
+                if (mResolverListCommunicator
+                        .resolveInfoMatch(dri.getResolveInfo(), existingInfo.getResolveInfo())) {
+                    return;
+                }
+            }
+            mDisplayList.add(dri);
+        }
+    }
+
+    @Nullable
+    public ResolveInfo resolveInfoForPosition(int position, boolean filtered) {
+        TargetInfo target = targetInfoForPosition(position, filtered);
+        if (target != null) {
+            return target.getResolveInfo();
+        }
+        return null;
+    }
+
+    @Nullable
+    public TargetInfo targetInfoForPosition(int position, boolean filtered) {
+        if (filtered) {
+            return getItem(position);
+        }
+        if (mDisplayList.size() > position) {
+            return mDisplayList.get(position);
+        }
+        return null;
+    }
+
+    public int getCount() {
+        int totalSize = mDisplayList == null || mDisplayList.isEmpty() ? mPlaceholderCount :
+                mDisplayList.size();
+        if (mFilterLastUsed && mLastChosenPosition >= 0) {
+            totalSize--;
+        }
+        return totalSize;
+    }
+
+    public int getUnfilteredCount() {
+        return mDisplayList.size();
+    }
+
+    @Nullable
+    public TargetInfo getItem(int position) {
+        if (mFilterLastUsed && mLastChosenPosition >= 0 && position >= mLastChosenPosition) {
+            position++;
+        }
+        if (mDisplayList.size() > position) {
+            return mDisplayList.get(position);
+        } else {
+            return null;
+        }
+    }
+
+    public long getItemId(int position) {
+        return position;
+    }
+
+    public int getDisplayResolveInfoCount() {
+        return mDisplayList.size();
+    }
+
+    public DisplayResolveInfo getDisplayResolveInfo(int index) {
+        // Used to query services. We only query services for primary targets, not alternates.
+        return mDisplayList.get(index);
+    }
+
+    public final View getView(int position, View convertView, ViewGroup parent) {
+        View view = convertView;
+        if (view == null) {
+            view = createView(parent);
+        }
+        onBindView(view, getItem(position));
+        return view;
+    }
+
+    public final View createView(ViewGroup parent) {
+        final View view = onCreateView(parent);
+        final ViewHolder holder = new ViewHolder(view);
+        view.setTag(holder);
+        return view;
+    }
+
+    public View onCreateView(ViewGroup parent) {
+        return mInflater.inflate(
+                com.android.internal.R.layout.resolve_list_item, parent, false);
+    }
+
+    public final void bindView(int position, View view) {
+        onBindView(view, getItem(position));
+    }
+
+    protected void onBindView(View view, TargetInfo info) {
+        final ViewHolder holder = (ViewHolder) view.getTag();
+        if (info == null) {
+            holder.icon.setImageDrawable(
+                    mContext.getDrawable(R.drawable.resolver_icon_placeholder));
+            return;
+        }
+
+        if (info instanceof DisplayResolveInfo
+                && !((DisplayResolveInfo) info).hasDisplayLabel()) {
+            getLoadLabelTask((DisplayResolveInfo) info, holder).execute();
+        } else {
+            holder.bindLabel(info.getDisplayLabel(), info.getExtendedInfo());
+        }
+
+        if (info.isSuspended()) {
+            holder.icon.setColorFilter(mSuspendedMatrixColorFilter);
+        } else {
+            holder.icon.setColorFilter(null);
+        }
+
+        if (info instanceof DisplayResolveInfo
+                && !((DisplayResolveInfo) info).hasDisplayIcon()) {
+            new ResolverListAdapter.LoadIconTask((DisplayResolveInfo) info, holder.icon).execute();
+        } else {
+            holder.icon.setImageDrawable(info.getDisplayIcon(mContext));
+        }
+    }
+
+    protected LoadLabelTask getLoadLabelTask(DisplayResolveInfo info, ViewHolder holder) {
+        return new LoadLabelTask(info, holder);
+    }
+
+    public void onDestroy() {
+        if (mPostListReadyRunnable != null) {
+            mContext.getMainThreadHandler().removeCallbacks(mPostListReadyRunnable);
+            mPostListReadyRunnable = null;
+        }
+        if (mResolverListController != null) {
+            mResolverListController.destroy();
+        }
+    }
+
+    private ColorMatrixColorFilter createSuspendedColorMatrix() {
+        int grayValue = 127;
+        float scale = 0.5f; // half bright
+
+        ColorMatrix tempBrightnessMatrix = new ColorMatrix();
+        float[] mat = tempBrightnessMatrix.getArray();
+        mat[0] = scale;
+        mat[6] = scale;
+        mat[12] = scale;
+        mat[4] = grayValue;
+        mat[9] = grayValue;
+        mat[14] = grayValue;
+
+        ColorMatrix matrix = new ColorMatrix();
+        matrix.setSaturation(0.0f);
+        matrix.preConcat(tempBrightnessMatrix);
+        return new ColorMatrixColorFilter(matrix);
+    }
+
+    ActivityInfoPresentationGetter makePresentationGetter(ActivityInfo ai) {
+        return new ActivityInfoPresentationGetter(mContext, mIconDpi, ai);
+    }
+
+    ResolveInfoPresentationGetter makePresentationGetter(ResolveInfo ri) {
+        return new ResolveInfoPresentationGetter(mContext, mIconDpi, ri);
+    }
+
+    Drawable loadIconForResolveInfo(ResolveInfo ri) {
+        // Load icons based on the current process. If in work profile icons should be badged.
+        return makePresentationGetter(ri).getIcon(Process.myUserHandle());
+    }
+
+    void loadFilteredItemIconTaskAsync(@NonNull ImageView iconView) {
+        final DisplayResolveInfo iconInfo = getFilteredItem();
+        if (iconView != null && iconInfo != null) {
+            new LoadIconTask(iconInfo, iconView).execute();
+        }
+    }
+
+    /**
+     * Necessary methods to communicate between {@link ResolverListAdapter}
+     * and {@link ResolverActivity}.
+     */
+    interface ResolverListCommunicator {
+
+        boolean resolveInfoMatch(ResolveInfo lhs, ResolveInfo rhs);
+
+        Intent getReplacementIntent(ActivityInfo activityInfo, Intent defIntent);
+
+        void onPostListReady();
+
+        void sendVoiceChoicesIfNeeded();
+
+        void updateProfileViewButton();
+
+        boolean useLayoutWithDefault();
+
+        boolean shouldGetActivityMetadata();
+
+        Intent getTargetIntent();
+
+        void onHandlePackagesChanged();
+    }
+
+    static class ViewHolder {
+        public View itemView;
+        public Drawable defaultItemViewBackground;
+
+        public TextView text;
+        public TextView text2;
+        public ImageView icon;
+
+        ViewHolder(View view) {
+            itemView = view;
+            defaultItemViewBackground = view.getBackground();
+            text = (TextView) view.findViewById(com.android.internal.R.id.text1);
+            text2 = (TextView) view.findViewById(com.android.internal.R.id.text2);
+            icon = (ImageView) view.findViewById(R.id.icon);
+        }
+
+        public void bindLabel(CharSequence label, CharSequence subLabel) {
+            if (!TextUtils.equals(text.getText(), label)) {
+                text.setText(label);
+            }
+
+            // Always show a subLabel for visual consistency across list items. Show an empty
+            // subLabel if the subLabel is the same as the label
+            if (TextUtils.equals(label, subLabel)) {
+                subLabel = null;
+            }
+
+            if (!TextUtils.equals(text2.getText(), subLabel)
+                    && !TextUtils.isEmpty(subLabel)) {
+                text2.setVisibility(View.VISIBLE);
+                text2.setText(subLabel);
+            }
+        }
+    }
+
+    protected class LoadLabelTask extends AsyncTask<Void, Void, CharSequence[]> {
+        private final DisplayResolveInfo mDisplayResolveInfo;
+        private final ViewHolder mHolder;
+
+        protected LoadLabelTask(DisplayResolveInfo dri, ViewHolder holder) {
+            mDisplayResolveInfo = dri;
+            mHolder = holder;
+        }
+
+        @Override
+        protected CharSequence[] doInBackground(Void... voids) {
+            ResolveInfoPresentationGetter pg =
+                    makePresentationGetter(mDisplayResolveInfo.getResolveInfo());
+
+            if (mIsAudioCaptureDevice) {
+                // This is an audio capture device, so check record permissions
+                ActivityInfo activityInfo = mDisplayResolveInfo.getResolveInfo().activityInfo;
+                String packageName = activityInfo.packageName;
+
+                int uid = activityInfo.applicationInfo.uid;
+                boolean hasRecordPermission =
+                        PermissionChecker.checkPermissionForPreflight(
+                                mContext,
+                                android.Manifest.permission.RECORD_AUDIO, -1, uid,
+                                packageName)
+                                == android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+                if (!hasRecordPermission) {
+                    // Doesn't have record permission, so warn the user
+                    return new CharSequence[] {
+                            pg.getLabel(),
+                            mContext.getString(R.string.usb_device_resolve_prompt_warn)
+                    };
+                }
+            }
+
+            return new CharSequence[] {
+                    pg.getLabel(),
+                    pg.getSubLabel()
+            };
+        }
+
+        @Override
+        protected void onPostExecute(CharSequence[] result) {
+            mDisplayResolveInfo.setDisplayLabel(result[0]);
+            mDisplayResolveInfo.setExtendedInfo(result[1]);
+            mHolder.bindLabel(result[0], result[1]);
+        }
+    }
+
+    class LoadIconTask extends AsyncTask<Void, Void, Drawable> {
+        protected final com.android.internal.app.chooser.DisplayResolveInfo mDisplayResolveInfo;
+        private final ResolveInfo mResolveInfo;
+        private final ImageView mTargetView;
+
+        LoadIconTask(DisplayResolveInfo dri, ImageView target) {
+            mDisplayResolveInfo = dri;
+            mResolveInfo = dri.getResolveInfo();
+            mTargetView = target;
+        }
+
+        @Override
+        protected Drawable doInBackground(Void... params) {
+            return loadIconForResolveInfo(mResolveInfo);
+        }
+
+        @Override
+        protected void onPostExecute(Drawable d) {
+            if (getOtherProfile() == mDisplayResolveInfo) {
+                mResolverListCommunicator.updateProfileViewButton();
+            } else {
+                mDisplayResolveInfo.setDisplayIcon(d);
+                mTargetView.setImageDrawable(d);
+            }
+        }
+    }
+
+    /**
+     * Loads the icon and label for the provided ResolveInfo.
+     */
+    @VisibleForTesting
+    public static class ResolveInfoPresentationGetter extends ActivityInfoPresentationGetter {
+        private final ResolveInfo mRi;
+        public ResolveInfoPresentationGetter(Context ctx, int iconDpi, ResolveInfo ri) {
+            super(ctx, iconDpi, ri.activityInfo);
+            mRi = ri;
+        }
+
+        @Override
+        Drawable getIconSubstituteInternal() {
+            Drawable dr = null;
+            try {
+                // Do not use ResolveInfo#getIconResource() as it defaults to the app
+                if (mRi.resolvePackageName != null && mRi.icon != 0) {
+                    dr = loadIconFromResource(
+                            mPm.getResourcesForApplication(mRi.resolvePackageName), mRi.icon);
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+                Log.e(TAG, "SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON permission granted but "
+                        + "couldn't find resources for package", e);
+            }
+
+            // Fall back to ActivityInfo if no icon is found via ResolveInfo
+            if (dr == null) dr = super.getIconSubstituteInternal();
+
+            return dr;
+        }
+
+        @Override
+        String getAppSubLabelInternal() {
+            // Will default to app name if no intent filter or activity label set, make sure to
+            // check if subLabel matches label before final display
+            return (String) mRi.loadLabel(mPm);
+        }
+    }
+
+    /**
+     * Loads the icon and label for the provided ActivityInfo.
+     */
+    @VisibleForTesting
+    public static class ActivityInfoPresentationGetter extends
+            TargetPresentationGetter {
+        private final ActivityInfo mActivityInfo;
+        public ActivityInfoPresentationGetter(Context ctx, int iconDpi,
+                ActivityInfo activityInfo) {
+            super(ctx, iconDpi, activityInfo.applicationInfo);
+            mActivityInfo = activityInfo;
+        }
+
+        @Override
+        Drawable getIconSubstituteInternal() {
+            Drawable dr = null;
+            try {
+                // Do not use ActivityInfo#getIconResource() as it defaults to the app
+                if (mActivityInfo.icon != 0) {
+                    dr = loadIconFromResource(
+                            mPm.getResourcesForApplication(mActivityInfo.applicationInfo),
+                            mActivityInfo.icon);
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+                Log.e(TAG, "SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON permission granted but "
+                        + "couldn't find resources for package", e);
+            }
+
+            return dr;
+        }
+
+        @Override
+        String getAppSubLabelInternal() {
+            // Will default to app name if no activity label set, make sure to check if subLabel
+            // matches label before final display
+            return (String) mActivityInfo.loadLabel(mPm);
+        }
+    }
+
+    /**
+     * Loads the icon and label for the provided ApplicationInfo. Defaults to using the application
+     * icon and label over any IntentFilter or Activity icon to increase user understanding, with an
+     * exception for applications that hold the right permission. Always attempts to use available
+     * resources over PackageManager loading mechanisms so badging can be done by iconloader. Uses
+     * Strings to strip creative formatting.
+     */
+    private abstract static class TargetPresentationGetter {
+        @Nullable abstract Drawable getIconSubstituteInternal();
+        @Nullable abstract String getAppSubLabelInternal();
+
+        private Context mCtx;
+        private final int mIconDpi;
+        private final boolean mHasSubstitutePermission;
+        private final ApplicationInfo mAi;
+
+        protected PackageManager mPm;
+
+        TargetPresentationGetter(Context ctx, int iconDpi, ApplicationInfo ai) {
+            mCtx = ctx;
+            mPm = ctx.getPackageManager();
+            mAi = ai;
+            mIconDpi = iconDpi;
+            mHasSubstitutePermission = PackageManager.PERMISSION_GRANTED == mPm.checkPermission(
+                    android.Manifest.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON,
+                    mAi.packageName);
+        }
+
+        public Drawable getIcon(UserHandle userHandle) {
+            return new BitmapDrawable(mCtx.getResources(), getIconBitmap(userHandle));
+        }
+
+        public Bitmap getIconBitmap(UserHandle userHandle) {
+            Drawable dr = null;
+            if (mHasSubstitutePermission) {
+                dr = getIconSubstituteInternal();
+            }
+
+            if (dr == null) {
+                try {
+                    if (mAi.icon != 0) {
+                        dr = loadIconFromResource(mPm.getResourcesForApplication(mAi), mAi.icon);
+                    }
+                } catch (PackageManager.NameNotFoundException ignore) {
+                }
+            }
+
+            // Fall back to ApplicationInfo#loadIcon if nothing has been loaded
+            if (dr == null) {
+                dr = mAi.loadIcon(mPm);
+            }
+
+            SimpleIconFactory sif = SimpleIconFactory.obtain(mCtx);
+            Bitmap icon = sif.createUserBadgedIconBitmap(dr, userHandle);
+            sif.recycle();
+
+            return icon;
+        }
+
+        public String getLabel() {
+            String label = null;
+            // Apps with the substitute permission will always show the sublabel as their label
+            if (mHasSubstitutePermission) {
+                label = getAppSubLabelInternal();
+            }
+
+            if (label == null) {
+                label = (String) mAi.loadLabel(mPm);
+            }
+
+            return label;
+        }
+
+        public String getSubLabel() {
+            // Apps with the substitute permission will never have a sublabel
+            if (mHasSubstitutePermission) return null;
+            return getAppSubLabelInternal();
+        }
+
+        protected String loadLabelFromResource(Resources res, int resId) {
+            return res.getString(resId);
+        }
+
+        @Nullable
+        protected Drawable loadIconFromResource(Resources res, int resId) {
+            return res.getDrawableForDensity(resId, mIconDpi);
+        }
+
+    }
+}
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index 28a8a86..6cc60b7 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -31,6 +31,7 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.chooser.DisplayResolveInfo;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -332,7 +333,7 @@
     }
 
     @VisibleForTesting
-    public float getScore(ResolverActivity.DisplayResolveInfo target) {
+    public float getScore(DisplayResolveInfo target) {
         return mResolverComparator.getScore(target.getResolvedComponentName());
     }
 
diff --git a/core/java/com/android/internal/app/SimpleIconFactory.java b/core/java/com/android/internal/app/SimpleIconFactory.java
index 7a4e76f..d618cdf 100644
--- a/core/java/com/android/internal/app/SimpleIconFactory.java
+++ b/core/java/com/android/internal/app/SimpleIconFactory.java
@@ -214,7 +214,7 @@
      * @deprecated Do not use, functionality will be replaced by iconloader lib eventually.
      */
     @Deprecated
-    Bitmap createAppBadgedIconBitmap(@Nullable Drawable icon, Bitmap renderedAppIcon) {
+    public Bitmap createAppBadgedIconBitmap(@Nullable Drawable icon, Bitmap renderedAppIcon) {
         // If no icon is provided use the system default
         if (icon == null) {
             icon = getFullResDefaultActivityIcon(mFillResIconDpi);
diff --git a/core/java/com/android/internal/app/chooser/ChooserTargetInfo.java b/core/java/com/android/internal/app/chooser/ChooserTargetInfo.java
new file mode 100644
index 0000000..a2d0953
--- /dev/null
+++ b/core/java/com/android/internal/app/chooser/ChooserTargetInfo.java
@@ -0,0 +1,53 @@
+/*
+ * 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.internal.app.chooser;
+
+import android.service.chooser.ChooserTarget;
+import android.text.TextUtils;
+
+/**
+ * A TargetInfo for Direct Share. Includes a {@link ChooserTarget} representing the
+ * Direct Share deep link into an application.
+ */
+public interface ChooserTargetInfo extends TargetInfo {
+    float getModifiedScore();
+
+    ChooserTarget getChooserTarget();
+
+    /**
+     * Do not label as 'equals', since this doesn't quite work
+     * as intended with java 8.
+     */
+    default boolean isSimilar(ChooserTargetInfo other) {
+        if (other == null) return false;
+
+        ChooserTarget ct1 = getChooserTarget();
+        ChooserTarget ct2 = other.getChooserTarget();
+
+        // If either is null, there is not enough info to make an informed decision
+        // about equality, so just exit
+        if (ct1 == null || ct2 == null) return false;
+
+        if (ct1.getComponentName().equals(ct2.getComponentName())
+                && TextUtils.equals(getDisplayLabel(), other.getDisplayLabel())
+                && TextUtils.equals(getExtendedInfo(), other.getExtendedInfo())) {
+            return true;
+        }
+
+        return false;
+    }
+}
diff --git a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
new file mode 100644
index 0000000..c77444e
--- /dev/null
+++ b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
@@ -0,0 +1,182 @@
+/*
+ * 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.internal.app.chooser;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ResolveInfo;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+import com.android.internal.app.ResolverActivity;
+import com.android.internal.app.ResolverListAdapter.ResolveInfoPresentationGetter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A TargetInfo plus additional information needed to render it (such as icon and label) and
+ * resolve it to an activity.
+ */
+public class DisplayResolveInfo implements TargetInfo {
+    // Temporary flag for new chooser delegate behavior.
+    private static final boolean ENABLE_CHOOSER_DELEGATE = true;
+
+    private final ResolveInfo mResolveInfo;
+    private CharSequence mDisplayLabel;
+    private Drawable mDisplayIcon;
+    private CharSequence mExtendedInfo;
+    private final Intent mResolvedIntent;
+    private final List<Intent> mSourceIntents = new ArrayList<>();
+    private boolean mIsSuspended;
+    private ResolveInfoPresentationGetter mResolveInfoPresentationGetter;
+
+    public DisplayResolveInfo(Intent originalIntent, ResolveInfo pri, Intent pOrigIntent,
+            ResolveInfoPresentationGetter resolveInfoPresentationGetter) {
+        this(originalIntent, pri, null /*mDisplayLabel*/, null /*mExtendedInfo*/, pOrigIntent,
+                resolveInfoPresentationGetter);
+    }
+
+    public DisplayResolveInfo(Intent originalIntent, ResolveInfo pri, CharSequence pLabel,
+            CharSequence pInfo, @NonNull Intent resolvedIntent,
+            @Nullable ResolveInfoPresentationGetter resolveInfoPresentationGetter) {
+        mSourceIntents.add(originalIntent);
+        mResolveInfo = pri;
+        mDisplayLabel = pLabel;
+        mExtendedInfo = pInfo;
+        mResolveInfoPresentationGetter = resolveInfoPresentationGetter;
+
+        final Intent intent = new Intent(resolvedIntent);
+        intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
+                | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
+        final ActivityInfo ai = mResolveInfo.activityInfo;
+        intent.setComponent(new ComponentName(ai.applicationInfo.packageName, ai.name));
+
+        mIsSuspended = (ai.applicationInfo.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
+
+        mResolvedIntent = intent;
+    }
+
+    private DisplayResolveInfo(DisplayResolveInfo other, Intent fillInIntent, int flags,
+            ResolveInfoPresentationGetter resolveInfoPresentationGetter) {
+        mSourceIntents.addAll(other.getAllSourceIntents());
+        mResolveInfo = other.mResolveInfo;
+        mDisplayLabel = other.mDisplayLabel;
+        mDisplayIcon = other.mDisplayIcon;
+        mExtendedInfo = other.mExtendedInfo;
+        mResolvedIntent = new Intent(other.mResolvedIntent);
+        mResolvedIntent.fillIn(fillInIntent, flags);
+        mResolveInfoPresentationGetter = resolveInfoPresentationGetter;
+    }
+
+    public ResolveInfo getResolveInfo() {
+        return mResolveInfo;
+    }
+
+    public CharSequence getDisplayLabel() {
+        if (mDisplayLabel == null && mResolveInfoPresentationGetter != null) {
+            mDisplayLabel = mResolveInfoPresentationGetter.getLabel();
+            mExtendedInfo = mResolveInfoPresentationGetter.getSubLabel();
+        }
+        return mDisplayLabel;
+    }
+
+    public boolean hasDisplayLabel() {
+        return mDisplayLabel != null;
+    }
+
+    public void setDisplayLabel(CharSequence displayLabel) {
+        mDisplayLabel = displayLabel;
+    }
+
+    public void setExtendedInfo(CharSequence extendedInfo) {
+        mExtendedInfo = extendedInfo;
+    }
+
+    public Drawable getDisplayIcon(Context context) {
+        return mDisplayIcon;
+    }
+
+    @Override
+    public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
+        return new DisplayResolveInfo(this, fillInIntent, flags, mResolveInfoPresentationGetter);
+    }
+
+    @Override
+    public List<Intent> getAllSourceIntents() {
+        return mSourceIntents;
+    }
+
+    public void addAlternateSourceIntent(Intent alt) {
+        mSourceIntents.add(alt);
+    }
+
+    public void setDisplayIcon(Drawable icon) {
+        mDisplayIcon = icon;
+    }
+
+    public boolean hasDisplayIcon() {
+        return mDisplayIcon != null;
+    }
+
+    public CharSequence getExtendedInfo() {
+        return mExtendedInfo;
+    }
+
+    public Intent getResolvedIntent() {
+        return mResolvedIntent;
+    }
+
+    @Override
+    public ComponentName getResolvedComponentName() {
+        return new ComponentName(mResolveInfo.activityInfo.packageName,
+                mResolveInfo.activityInfo.name);
+    }
+
+    @Override
+    public boolean start(Activity activity, Bundle options) {
+        activity.startActivity(mResolvedIntent, options);
+        return true;
+    }
+
+    @Override
+    public boolean startAsCaller(ResolverActivity activity, Bundle options, int userId) {
+        if (ENABLE_CHOOSER_DELEGATE) {
+            return activity.startAsCallerImpl(mResolvedIntent, options, false, userId);
+        } else {
+            activity.startActivityAsCaller(mResolvedIntent, options, null, false, userId);
+            return true;
+        }
+    }
+
+    @Override
+    public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
+        activity.startActivityAsUser(mResolvedIntent, options, user);
+        return false;
+    }
+
+    public boolean isSuspended() {
+        return mIsSuspended;
+    }
+}
diff --git a/core/java/com/android/internal/app/chooser/NotSelectableTargetInfo.java b/core/java/com/android/internal/app/chooser/NotSelectableTargetInfo.java
new file mode 100644
index 0000000..22cbdaa6
--- /dev/null
+++ b/core/java/com/android/internal/app/chooser/NotSelectableTargetInfo.java
@@ -0,0 +1,88 @@
+/*
+ * 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.internal.app.chooser;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.service.chooser.ChooserTarget;
+
+import com.android.internal.app.ResolverActivity;
+
+import java.util.List;
+
+/**
+ * Distinguish between targets that selectable by the user, vs those that are
+ * placeholders for the system while information is loading in an async manner.
+ */
+public abstract class NotSelectableTargetInfo implements ChooserTargetInfo {
+
+    public Intent getResolvedIntent() {
+        return null;
+    }
+
+    public ComponentName getResolvedComponentName() {
+        return null;
+    }
+
+    public boolean start(Activity activity, Bundle options) {
+        return false;
+    }
+
+    public boolean startAsCaller(ResolverActivity activity, Bundle options, int userId) {
+        return false;
+    }
+
+    public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
+        return false;
+    }
+
+    public ResolveInfo getResolveInfo() {
+        return null;
+    }
+
+    public CharSequence getDisplayLabel() {
+        return null;
+    }
+
+    public CharSequence getExtendedInfo() {
+        return null;
+    }
+
+    public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
+        return null;
+    }
+
+    public List<Intent> getAllSourceIntents() {
+        return null;
+    }
+
+    public float getModifiedScore() {
+        return -0.1f;
+    }
+
+    public ChooserTarget getChooserTarget() {
+        return null;
+    }
+
+    public boolean isSuspended() {
+        return false;
+    }
+}
diff --git a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
new file mode 100644
index 0000000..1cc4857
--- /dev/null
+++ b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
@@ -0,0 +1,316 @@
+/*
+ * 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.internal.app.chooser;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.LauncherApps;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ShortcutInfo;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.service.chooser.ChooserTarget;
+import android.text.SpannableStringBuilder;
+import android.util.Log;
+
+import com.android.internal.app.ChooserActivity;
+import com.android.internal.app.ChooserFlags;
+import com.android.internal.app.ResolverActivity;
+import com.android.internal.app.ResolverListAdapter.ActivityInfoPresentationGetter;
+import com.android.internal.app.SimpleIconFactory;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Live target, currently selectable by the user.
+ * @see NotSelectableTargetInfo
+ */
+public final class SelectableTargetInfo implements ChooserTargetInfo {
+    private static final String TAG = "SelectableTargetInfo";
+
+    private final Context mContext;
+    private final DisplayResolveInfo mSourceInfo;
+    private final ResolveInfo mBackupResolveInfo;
+    private final ChooserTarget mChooserTarget;
+    private final String mDisplayLabel;
+    private final PackageManager mPm;
+    private final SelectableTargetInfoCommunicator mSelectableTargetInfoCommunicator;
+    private Drawable mBadgeIcon = null;
+    private CharSequence mBadgeContentDescription;
+    private Drawable mDisplayIcon;
+    private final Intent mFillInIntent;
+    private final int mFillInFlags;
+    private final float mModifiedScore;
+    private boolean mIsSuspended = false;
+
+    public SelectableTargetInfo(Context context, DisplayResolveInfo sourceInfo,
+            ChooserTarget chooserTarget,
+            float modifiedScore, SelectableTargetInfoCommunicator selectableTargetInfoComunicator) {
+        mContext = context;
+        mSourceInfo = sourceInfo;
+        mChooserTarget = chooserTarget;
+        mModifiedScore = modifiedScore;
+        mPm = mContext.getPackageManager();
+        mSelectableTargetInfoCommunicator = selectableTargetInfoComunicator;
+        if (sourceInfo != null) {
+            final ResolveInfo ri = sourceInfo.getResolveInfo();
+            if (ri != null) {
+                final ActivityInfo ai = ri.activityInfo;
+                if (ai != null && ai.applicationInfo != null) {
+                    final PackageManager pm = mContext.getPackageManager();
+                    mBadgeIcon = pm.getApplicationIcon(ai.applicationInfo);
+                    mBadgeContentDescription = pm.getApplicationLabel(ai.applicationInfo);
+                    mIsSuspended =
+                            (ai.applicationInfo.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
+                }
+            }
+        }
+        // TODO(b/121287224): do this in the background thread, and only for selected targets
+        mDisplayIcon = getChooserTargetIconDrawable(chooserTarget);
+
+        if (sourceInfo != null) {
+            mBackupResolveInfo = null;
+        } else {
+            mBackupResolveInfo =
+                    mContext.getPackageManager().resolveActivity(getResolvedIntent(), 0);
+        }
+
+        mFillInIntent = null;
+        mFillInFlags = 0;
+
+        mDisplayLabel = sanitizeDisplayLabel(chooserTarget.getTitle());
+    }
+
+    private SelectableTargetInfo(SelectableTargetInfo other,
+            Intent fillInIntent, int flags) {
+        mContext = other.mContext;
+        mPm = other.mPm;
+        mSelectableTargetInfoCommunicator = other.mSelectableTargetInfoCommunicator;
+        mSourceInfo = other.mSourceInfo;
+        mBackupResolveInfo = other.mBackupResolveInfo;
+        mChooserTarget = other.mChooserTarget;
+        mBadgeIcon = other.mBadgeIcon;
+        mBadgeContentDescription = other.mBadgeContentDescription;
+        mDisplayIcon = other.mDisplayIcon;
+        mFillInIntent = fillInIntent;
+        mFillInFlags = flags;
+        mModifiedScore = other.mModifiedScore;
+
+        mDisplayLabel = sanitizeDisplayLabel(mChooserTarget.getTitle());
+    }
+
+    private String sanitizeDisplayLabel(CharSequence label) {
+        SpannableStringBuilder sb = new SpannableStringBuilder(label);
+        sb.clearSpans();
+        return sb.toString();
+    }
+
+    public boolean isSuspended() {
+        return mIsSuspended;
+    }
+
+    /**
+     * Since ShortcutInfos are returned by ShortcutManager, we can cache the shortcuts and skip
+     * the call to LauncherApps#getShortcuts(ShortcutQuery).
+     */
+    // TODO(121287224): Refactor code to apply the suggestion above
+    private Drawable getChooserTargetIconDrawable(ChooserTarget target) {
+        Drawable directShareIcon = null;
+
+        // First get the target drawable and associated activity info
+        final Icon icon = target.getIcon();
+        if (icon != null) {
+            directShareIcon = icon.loadDrawable(mContext);
+        } else if (ChooserFlags.USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS) {
+            Bundle extras = target.getIntentExtras();
+            if (extras != null && extras.containsKey(Intent.EXTRA_SHORTCUT_ID)) {
+                CharSequence shortcutId = extras.getCharSequence(Intent.EXTRA_SHORTCUT_ID);
+                LauncherApps launcherApps = (LauncherApps) mContext.getSystemService(
+                        Context.LAUNCHER_APPS_SERVICE);
+                final LauncherApps.ShortcutQuery q = new LauncherApps.ShortcutQuery();
+                q.setPackage(target.getComponentName().getPackageName());
+                q.setShortcutIds(Arrays.asList(shortcutId.toString()));
+                q.setQueryFlags(LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC);
+                final List<ShortcutInfo> shortcuts =
+                        launcherApps.getShortcuts(q, mContext.getUser());
+                if (shortcuts != null && shortcuts.size() > 0) {
+                    directShareIcon = launcherApps.getShortcutIconDrawable(shortcuts.get(0), 0);
+                }
+            }
+        }
+
+        if (directShareIcon == null) return null;
+
+        ActivityInfo info = null;
+        try {
+            info = mPm.getActivityInfo(target.getComponentName(), 0);
+        } catch (PackageManager.NameNotFoundException error) {
+            Log.e(TAG, "Could not find activity associated with ChooserTarget");
+        }
+
+        if (info == null) return null;
+
+        // Now fetch app icon and raster with no badging even in work profile
+        Bitmap appIcon = mSelectableTargetInfoCommunicator.makePresentationGetter(info)
+                .getIconBitmap(UserHandle.getUserHandleForUid(UserHandle.myUserId()));
+
+        // Raster target drawable with appIcon as a badge
+        SimpleIconFactory sif = SimpleIconFactory.obtain(mContext);
+        Bitmap directShareBadgedIcon = sif.createAppBadgedIconBitmap(directShareIcon, appIcon);
+        sif.recycle();
+
+        return new BitmapDrawable(mContext.getResources(), directShareBadgedIcon);
+    }
+
+    public float getModifiedScore() {
+        return mModifiedScore;
+    }
+
+    @Override
+    public Intent getResolvedIntent() {
+        if (mSourceInfo != null) {
+            return mSourceInfo.getResolvedIntent();
+        }
+
+        final Intent targetIntent = new Intent(mSelectableTargetInfoCommunicator.getTargetIntent());
+        targetIntent.setComponent(mChooserTarget.getComponentName());
+        targetIntent.putExtras(mChooserTarget.getIntentExtras());
+        return targetIntent;
+    }
+
+    @Override
+    public ComponentName getResolvedComponentName() {
+        if (mSourceInfo != null) {
+            return mSourceInfo.getResolvedComponentName();
+        } else if (mBackupResolveInfo != null) {
+            return new ComponentName(mBackupResolveInfo.activityInfo.packageName,
+                    mBackupResolveInfo.activityInfo.name);
+        }
+        return null;
+    }
+
+    private Intent getBaseIntentToSend() {
+        Intent result = getResolvedIntent();
+        if (result == null) {
+            Log.e(TAG, "ChooserTargetInfo: no base intent available to send");
+        } else {
+            result = new Intent(result);
+            if (mFillInIntent != null) {
+                result.fillIn(mFillInIntent, mFillInFlags);
+            }
+            result.fillIn(mSelectableTargetInfoCommunicator.getReferrerFillInIntent(), 0);
+        }
+        return result;
+    }
+
+    @Override
+    public boolean start(Activity activity, Bundle options) {
+        throw new RuntimeException("ChooserTargets should be started as caller.");
+    }
+
+    @Override
+    public boolean startAsCaller(ResolverActivity activity, Bundle options, int userId) {
+        final Intent intent = getBaseIntentToSend();
+        if (intent == null) {
+            return false;
+        }
+        intent.setComponent(mChooserTarget.getComponentName());
+        intent.putExtras(mChooserTarget.getIntentExtras());
+
+        // Important: we will ignore the target security checks in ActivityManager
+        // if and only if the ChooserTarget's target package is the same package
+        // where we got the ChooserTargetService that provided it. This lets a
+        // ChooserTargetService provide a non-exported or permission-guarded target
+        // to the chooser for the user to pick.
+        //
+        // If mSourceInfo is null, we got this ChooserTarget from the caller or elsewhere
+        // so we'll obey the caller's normal security checks.
+        final boolean ignoreTargetSecurity = mSourceInfo != null
+                && mSourceInfo.getResolvedComponentName().getPackageName()
+                .equals(mChooserTarget.getComponentName().getPackageName());
+        return activity.startAsCallerImpl(intent, options, ignoreTargetSecurity, userId);
+    }
+
+    @Override
+    public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
+        throw new RuntimeException("ChooserTargets should be started as caller.");
+    }
+
+    @Override
+    public ResolveInfo getResolveInfo() {
+        return mSourceInfo != null ? mSourceInfo.getResolveInfo() : mBackupResolveInfo;
+    }
+
+    @Override
+    public CharSequence getDisplayLabel() {
+        return mDisplayLabel;
+    }
+
+    @Override
+    public CharSequence getExtendedInfo() {
+        // ChooserTargets have badge icons, so we won't show the extended info to disambiguate.
+        return null;
+    }
+
+    @Override
+    public Drawable getDisplayIcon(Context context) {
+        return mDisplayIcon;
+    }
+
+    public ChooserTarget getChooserTarget() {
+        return mChooserTarget;
+    }
+
+    @Override
+    public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
+        return new SelectableTargetInfo(this, fillInIntent, flags);
+    }
+
+    @Override
+    public List<Intent> getAllSourceIntents() {
+        final List<Intent> results = new ArrayList<>();
+        if (mSourceInfo != null) {
+            // We only queried the service for the first one in our sourceinfo.
+            results.add(mSourceInfo.getAllSourceIntents().get(0));
+        }
+        return results;
+    }
+
+    /**
+     * Necessary methods to communicate between {@link SelectableTargetInfo}
+     * and {@link ResolverActivity} or {@link ChooserActivity}.
+     */
+    public interface SelectableTargetInfoCommunicator {
+
+        ActivityInfoPresentationGetter makePresentationGetter(ActivityInfo info);
+
+        Intent getTargetIntent();
+
+        Intent getReferrerFillInIntent();
+    }
+}
diff --git a/core/java/com/android/internal/app/chooser/TargetInfo.java b/core/java/com/android/internal/app/chooser/TargetInfo.java
new file mode 100644
index 0000000..b59def1
--- /dev/null
+++ b/core/java/com/android/internal/app/chooser/TargetInfo.java
@@ -0,0 +1,128 @@
+/*
+ * 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.internal.app.chooser;
+
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+import com.android.internal.app.ResolverActivity;
+
+import java.util.List;
+
+/**
+ * A single target as represented in the chooser.
+ */
+public interface TargetInfo {
+    /**
+     * Get the resolved intent that represents this target. Note that this may not be the
+     * intent that will be launched by calling one of the <code>start</code> methods provided;
+     * this is the intent that will be credited with the launch.
+     *
+     * @return the resolved intent for this target
+     */
+    Intent getResolvedIntent();
+
+    /**
+     * Get the resolved component name that represents this target. Note that this may not
+     * be the component that will be directly launched by calling one of the <code>start</code>
+     * methods provided; this is the component that will be credited with the launch.
+     *
+     * @return the resolved ComponentName for this target
+     */
+    ComponentName getResolvedComponentName();
+
+    /**
+     * Start the activity referenced by this target.
+     *
+     * @param activity calling Activity performing the launch
+     * @param options ActivityOptions bundle
+     * @return true if the start completed successfully
+     */
+    boolean start(Activity activity, Bundle options);
+
+    /**
+     * Start the activity referenced by this target as if the ResolverActivity's caller
+     * was performing the start operation.
+     *
+     * @param activity calling Activity (actually) performing the launch
+     * @param options ActivityOptions bundle
+     * @param userId userId to start as or {@link UserHandle#USER_NULL} for activity's caller
+     * @return true if the start completed successfully
+     */
+    boolean startAsCaller(ResolverActivity activity, Bundle options, int userId);
+
+    /**
+     * Start the activity referenced by this target as a given user.
+     *
+     * @param activity calling activity performing the launch
+     * @param options ActivityOptions bundle
+     * @param user handle for the user to start the activity as
+     * @return true if the start completed successfully
+     */
+    boolean startAsUser(Activity activity, Bundle options, UserHandle user);
+
+    /**
+     * Return the ResolveInfo about how and why this target matched the original query
+     * for available targets.
+     *
+     * @return ResolveInfo representing this target's match
+     */
+    ResolveInfo getResolveInfo();
+
+    /**
+     * Return the human-readable text label for this target.
+     *
+     * @return user-visible target label
+     */
+    CharSequence getDisplayLabel();
+
+    /**
+     * Return any extended info for this target. This may be used to disambiguate
+     * otherwise identical targets.
+     *
+     * @return human-readable disambig string or null if none present
+     */
+    CharSequence getExtendedInfo();
+
+    /**
+     * @return The drawable that should be used to represent this target including badge
+     * @param context
+     */
+    Drawable getDisplayIcon(Context context);
+
+    /**
+     * Clone this target with the given fill-in information.
+     */
+    TargetInfo cloneFilledIn(Intent fillInIntent, int flags);
+
+    /**
+     * @return the list of supported source intents deduped against this single target
+     */
+    List<Intent> getAllSourceIntents();
+
+    /**
+     * @return true if this target can be selected by the user
+     */
+    boolean isSuspended();
+}
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index 2f9136a..392b8d3 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -77,7 +77,6 @@
         STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT
         STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT_UI
         STATE_TOP,                      // ActivityManager.PROCESS_STATE_TOP
-        STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION
         STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_BOUND_TOP
         STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
         STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
diff --git a/core/java/com/android/internal/compat/CompatibilityChangeConfig.java b/core/java/com/android/internal/compat/CompatibilityChangeConfig.java
index fd2ada0..36bc229 100644
--- a/core/java/com/android/internal/compat/CompatibilityChangeConfig.java
+++ b/core/java/com/android/internal/compat/CompatibilityChangeConfig.java
@@ -49,6 +49,18 @@
         return mChangeConfig.forceDisabledSet();
     }
 
+    /**
+     * Returns if a change is enabled or disabled in this config.
+     */
+    public boolean isChangeEnabled(long changeId) {
+        if (mChangeConfig.isForceEnabled(changeId)) {
+            return true;
+        } else if (mChangeConfig.isForceDisabled(changeId)) {
+            return false;
+        }
+        throw new IllegalStateException("Change " + changeId + " is not defined.");
+    }
+
     private CompatibilityChangeConfig(Parcel in) {
         long[] enabledArray = in.createLongArray();
         long[] disabledArray = in.createLongArray();
diff --git a/core/java/com/android/internal/compat/CompatibilityChangeInfo.aidl b/core/java/com/android/internal/compat/CompatibilityChangeInfo.aidl
new file mode 100644
index 0000000..3bc7277
--- /dev/null
+++ b/core/java/com/android/internal/compat/CompatibilityChangeInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.internal.compat;
+
+parcelable CompatibilityChangeInfo;
diff --git a/core/java/com/android/internal/compat/CompatibilityChangeInfo.java b/core/java/com/android/internal/compat/CompatibilityChangeInfo.java
new file mode 100644
index 0000000..e48e2df
--- /dev/null
+++ b/core/java/com/android/internal/compat/CompatibilityChangeInfo.java
@@ -0,0 +1,92 @@
+/*
+ * 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.internal.compat;
+
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class is a parcelable version of {@link com.android.server.compat.Change}.
+ *
+ * @hide
+ */
+public class CompatibilityChangeInfo implements Parcelable {
+    private final long mChangeId;
+    private final @Nullable String mName;
+    private final int mEnableAfterTargetSdk;
+    private final boolean mDisabled;
+
+    public long getId() {
+        return mChangeId;
+    }
+
+    @Nullable
+    public String getName() {
+        return mName;
+    }
+
+    public int getEnableAfterTargetSdk() {
+        return mEnableAfterTargetSdk;
+    }
+
+    public boolean getDisabled() {
+        return mDisabled;
+    }
+
+    public CompatibilityChangeInfo(
+            Long changeId, String name, int enableAfterTargetSdk, boolean disabled) {
+        this.mChangeId = changeId;
+        this.mName = name;
+        this.mEnableAfterTargetSdk = enableAfterTargetSdk;
+        this.mDisabled = disabled;
+    }
+
+    private CompatibilityChangeInfo(Parcel in) {
+        mChangeId = in.readLong();
+        mName = in.readString();
+        mEnableAfterTargetSdk = in.readInt();
+        mDisabled = in.readBoolean();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(mChangeId);
+        dest.writeString(mName);
+        dest.writeInt(mEnableAfterTargetSdk);
+        dest.writeBoolean(mDisabled);
+    }
+
+    public static final Parcelable.Creator<CompatibilityChangeInfo> CREATOR =
+            new Parcelable.Creator<CompatibilityChangeInfo>() {
+
+                @Override
+                public CompatibilityChangeInfo createFromParcel(Parcel in) {
+                    return new CompatibilityChangeInfo(in);
+                }
+
+                @Override
+                public CompatibilityChangeInfo[] newArray(int size) {
+                    return new CompatibilityChangeInfo[size];
+                }
+            };
+}
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index 4099cfa..5857642 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -17,8 +17,10 @@
 package com.android.internal.compat;
 
 import android.content.pm.ApplicationInfo;
+import java.util.Map;
 
 parcelable CompatibilityChangeConfig;
+parcelable CompatibilityChangeInfo;
 
 /**
  * Platform private API for talking with the PlatformCompat service.
@@ -49,9 +51,10 @@
      * you do not need to call this API directly. The change will be reported for you.
      *
      * @param changeId    The ID of the compatibility change taking effect.
+     * @param userId      The ID of the user that the operation is done for.
      * @param packageName The package name of the app in question.
      */
-     void reportChangeByPackageName(long changeId, in String packageName);
+     void reportChangeByPackageName(long changeId, in String packageName, int userId);
 
     /**
      * Reports that a compatibility change is affecting an app process now.
@@ -86,7 +89,7 @@
      * be called when implementing functionality on behalf of the affected app.
      *
      * <p>Same as {@link #isChangeEnabled(long, ApplicationInfo)}, except it receives a package name
-     * instead of an {@link ApplicationInfo}
+     * and userId instead of an {@link ApplicationInfo}
      * object, and finds an app info object based on the package name. Returns {@code true} if
      * there is no installed package by that name.
      *
@@ -100,9 +103,10 @@
      *
      * @param changeId    The ID of the compatibility change in question.
      * @param packageName The package name of the app in question.
+     * @param userId      The ID of the user that the operation is done for.
      * @return {@code true} if the change is enabled for the current app.
      */
-    boolean isChangeEnabledByPackageName(long changeId, in String packageName);
+    boolean isChangeEnabledByPackageName(long changeId, in String packageName, int userId);
 
     /**
      * Query if a given compatibility change is enabled for an app process. This method should
@@ -144,4 +148,21 @@
      *
      */
     void clearOverrides(in String packageName);
+
+    /**
+     * Get configs for an application.
+     *
+     * @param appInfo The application whose config will be returned.
+     *
+     * @return A {@link CompatibilityChangeConfig}, representing whether a change is enabled for
+     *         the given app or not.
+     */
+    CompatibilityChangeConfig getAppConfig(in ApplicationInfo appInfo);
+
+    /**
+     * List all compatibility changes.
+     *
+     * @return An array of {@link CompatChangeInfo} known to the service.
+     */
+    CompatibilityChangeInfo[] listAllChanges();
 }
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 033e9b2..36a7a9c 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -337,6 +337,14 @@
             "brightline_falsing_zigzag_y_secondary_deviance";
 
 
+    // Flags related to screenshots
+
+    /**
+     * (boolean) Whether screenshot flow going to the corner (instead of shown in a notification)
+     * is enabled.
+     */
+    public static final String SCREENSHOT_CORNER_FLOW = "screenshot_corner_flow";
+
     private SystemUiDeviceConfigFlags() {
     }
 }
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
index 025e27b..382a254 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
@@ -168,9 +168,6 @@
         if ((startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0) {
             joiner.add("IS_TEXT_EDITOR");
         }
-        if ((startInputFlags & StartInputFlags.FIRST_WINDOW_FOCUS_GAIN) != 0) {
-            joiner.add("FIRST_WINDOW_FOCUS_GAIN");
-        }
         if ((startInputFlags & StartInputFlags.INITIAL_CONNECTION) != 0) {
             joiner.add("INITIAL_CONNECTION");
         }
diff --git a/core/java/com/android/internal/inputmethod/StartInputFlags.java b/core/java/com/android/internal/inputmethod/StartInputFlags.java
index ba26d8d..5a8d2c2 100644
--- a/core/java/com/android/internal/inputmethod/StartInputFlags.java
+++ b/core/java/com/android/internal/inputmethod/StartInputFlags.java
@@ -30,7 +30,6 @@
 @IntDef(flag = true, value = {
         StartInputFlags.VIEW_HAS_FOCUS,
         StartInputFlags.IS_TEXT_EDITOR,
-        StartInputFlags.FIRST_WINDOW_FOCUS_GAIN,
         StartInputFlags.INITIAL_CONNECTION})
 public @interface StartInputFlags {
     /**
@@ -44,13 +43,8 @@
     int IS_TEXT_EDITOR = 2;
 
     /**
-     * This is the first time the window has gotten focus.
-     */
-    int FIRST_WINDOW_FOCUS_GAIN = 4;
-
-    /**
      * An internal concept to distinguish "start" and "restart". This concept doesn't look well
      * documented hence we probably need to revisit this though.
      */
-    int INITIAL_CONNECTION = 8;
+    int INITIAL_CONNECTION = 4;
 }
diff --git a/core/java/com/android/internal/os/BaseCommand.java b/core/java/com/android/internal/os/BaseCommand.java
index 278f406..e1b8e6c 100644
--- a/core/java/com/android/internal/os/BaseCommand.java
+++ b/core/java/com/android/internal/os/BaseCommand.java
@@ -18,14 +18,14 @@
 package com.android.internal.os;
 
 import android.annotation.UnsupportedAppUsage;
-import android.os.ShellCommand;
+import android.os.BasicShellCommandHandler;
 
 import java.io.PrintStream;
 
 public abstract class BaseCommand {
 
     @UnsupportedAppUsage
-    final protected ShellCommand mArgs = new ShellCommand() {
+    final protected BasicShellCommandHandler mArgs = new BasicShellCommandHandler() {
         @Override public int onCommand(String cmd) {
             return 0;
         }
@@ -50,7 +50,7 @@
         }
 
         mRawArgs = args;
-        mArgs.init(null, null, null, null, args, null, 0);
+        mArgs.init(null, null, null, null, args, 0);
 
         try {
             onRun();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 9bddd2a..d6b32b5 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -12668,23 +12668,23 @@
         for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
             timeSignalStrengthTimeMs[i] = getWifiSignalStrengthTime(i, rawRealTime, which) / 1000;
         }
-        s.setLoggingDurationMs(computeBatteryRealtime(rawRealTime, which) / 1000);
-        s.setKernelActiveTimeMs(getWifiActiveTime(rawRealTime, which) / 1000);
+        s.setLoggingDurationMillis(computeBatteryRealtime(rawRealTime, which) / 1000);
+        s.setKernelActiveTimeMillis(getWifiActiveTime(rawRealTime, which) / 1000);
         s.setNumPacketsTx(getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which));
         s.setNumBytesTx(getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which));
         s.setNumPacketsRx(getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which));
         s.setNumBytesRx(getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which));
-        s.setSleepTimeMs(sleepTimeMs);
-        s.setIdleTimeMs(idleTimeMs);
-        s.setRxTimeMs(rxTimeMs);
-        s.setTxTimeMs(txTimeMs);
-        s.setScanTimeMs(scanTimeMs);
-        s.setEnergyConsumedMaMs(energyConsumedMaMs);
+        s.setSleepTimeMillis(sleepTimeMs);
+        s.setIdleTimeMillis(idleTimeMs);
+        s.setRxTimeMillis(rxTimeMs);
+        s.setTxTimeMillis(txTimeMs);
+        s.setScanTimeMillis(scanTimeMs);
+        s.setEnergyConsumedMaMillis(energyConsumedMaMs);
         s.setNumAppScanRequest(numAppScanRequest);
-        s.setTimeInStateMs(timeInStateMs);
-        s.setTimeInSupplicantStateMs(timeInSupplStateMs);
-        s.setTimeInRxSignalStrengthLevelMs(timeSignalStrengthTimeMs);
-        s.setMonitoredRailChargeConsumedMaMs(monitoredRailChargeConsumedMaMs);
+        s.setTimeInStateMillis(timeInStateMs);
+        s.setTimeInSupplicantStateMillis(timeInSupplStateMs);
+        s.setTimeInRxSignalStrengthLevelMillis(timeSignalStrengthTimeMs);
+        s.setMonitoredRailChargeConsumedMaMillis(monitoredRailChargeConsumedMaMs);
         return s;
     }
 
diff --git a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
index e6d044f..f1eb2fb 100644
--- a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
+++ b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
@@ -403,7 +403,7 @@
         }
 
         private long[] readFreqs(String line) {
-            if (line == null) {
+            if (line == null || line.trim().isEmpty()) {
                 return null;
             }
             final String[] lineArray = line.split(" ");
@@ -620,14 +620,18 @@
                 return true;
             }
 
-            String str = line.toString();
+            String str = line.toString().trim();
+            if (str.isEmpty()) {
+                Slog.w(mTag, "Empty uid_concurrent_active_time");
+                return false;
+            }
             if (!str.startsWith("cpus:")) {
-                Slog.wtf(mTag, "Malformed uid_concurrent_active_time line: " + line);
+                Slog.wtf(mTag, "Malformed uid_concurrent_active_time line: " + str);
                 return false;
             }
             int cores = Integer.parseInt(str.substring(5).trim(), 10);
             if (cores <= 0) {
-                Slog.wtf(mTag, "Malformed uid_concurrent_active_time line: " + line);
+                Slog.wtf(mTag, "Malformed uid_concurrent_active_time line: " + str);
                 return false;
             }
             mCores = cores;
@@ -750,17 +754,22 @@
             if (mNumClusters > 0) {
                 return true;
             }
+            String lineStr = line.toString().trim();
+            if (lineStr.isEmpty()) {
+                Slog.w(mTag, "Empty uid_concurrent_policy_time");
+                return false;
+            }
             // Parse # cores in clusters.
-            String[] lineArray = line.toString().split(" ");
+            String[] lineArray = lineStr.split(" ");
             if (lineArray.length % 2 != 0) {
-                Slog.wtf(mTag, "Malformed uid_concurrent_policy_time line: " + line);
+                Slog.wtf(mTag, "Malformed uid_concurrent_policy_time line: " + lineStr);
                 return false;
             }
             int[] clusters = new int[lineArray.length / 2];
             int cores = 0;
             for (int i = 0; i < clusters.length; i++) {
                 if (!lineArray[i * 2].startsWith("policy")) {
-                    Slog.wtf(mTag, "Malformed uid_concurrent_policy_time line: " + line);
+                    Slog.wtf(mTag, "Malformed uid_concurrent_policy_time line: " + lineStr);
                     return false;
                 }
                 clusters[i] = Integer.parseInt(lineArray[i * 2 + 1], 10);
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 363e549..865ec27 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -254,6 +254,18 @@
 
         InputStream is;
         try {
+            // If we are profiling the boot image, avoid preloading classes.
+            // Can't use device_config since we are the zygote.
+            String prop = SystemProperties.get(
+                    "persist.device_config.runtime_native_boot.profilebootclasspath", "");
+            // Might be empty if the property is unset since the default is "".
+            if (prop.length() == 0) {
+                prop = SystemProperties.get("dalvik.vm.profilebootclasspath", "");
+            }
+            if ("true".equals(prop)) {
+                return;
+            }
+
             is = new FileInputStream(PRELOADED_CLASSES);
         } catch (FileNotFoundException e) {
             Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 499a4d2..d703b86 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -21,6 +21,7 @@
 import android.content.ComponentName;
 import android.graphics.Rect;
 import android.os.Bundle;
+import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.hardware.biometrics.IBiometricServiceReceiverInternal;
 
@@ -78,7 +79,8 @@
     void onNotificationSettingsViewed(String key);
     void setSystemUiVisibility(int displayId, int vis, int mask, String cause);
     void onNotificationBubbleChanged(String key, boolean isBubble);
-    void grantInlineReplyUriPermission(String key, in Uri uri);
+    void grantInlineReplyUriPermission(String key, in Uri uri, in UserHandle user, String packageName);
+    void clearInlineReplyUriPermissions(String key);
 
     void onGlobalActionsShown();
     void onGlobalActionsHidden();
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index ea0389f..ed7f5de 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -26,6 +26,7 @@
 import android.os.Environment;
 import android.os.Process;
 import android.os.SystemProperties;
+import android.os.Trace;
 import android.os.storage.StorageManager;
 import android.permission.PermissionManager.SplitPermissionInfo;
 import android.text.TextUtils;
@@ -33,6 +34,7 @@
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.TimingsTraceLog;
 import android.util.Xml;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -411,7 +413,13 @@
     }
 
     SystemConfig() {
-        readAllPermissions();
+        TimingsTraceLog log = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
+        log.traceBegin("readAllPermissions");
+        try {
+            readAllPermissions();
+        } finally {
+            log.traceEnd();
+        }
     }
 
     private void readAllPermissions() {
@@ -532,6 +540,7 @@
             Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
             return;
         }
+        Slog.i(TAG, "Reading permissions from " + permFile);
 
         final boolean lowRam = ActivityManager.isLowRamDeviceStatic();
 
@@ -855,11 +864,7 @@
                         XmlUtils.skipCurrentTag(parser);
                     } break;
                     case "component-override": {
-                        if (allowAppConfigs) {
-                            readComponentOverrides(parser, permFile);
-                        } else {
-                            logNotAllowedInPartition(name, permFile, parser);
-                        }
+                        readComponentOverrides(parser, permFile);
                         XmlUtils.skipCurrentTag(parser);
                     } break;
                     case "backup-transport-whitelisted-service": {
diff --git a/core/jni/android_graphics_Picture.cpp b/core/jni/android_graphics_Picture.cpp
index 03fcdef..1d085e5 100644
--- a/core/jni/android_graphics_Picture.cpp
+++ b/core/jni/android_graphics_Picture.cpp
@@ -20,9 +20,12 @@
 #include "SkCanvas.h"
 #include "SkStream.h"
 #include "core_jni_helpers.h"
+#include "nativehelper/jni_macros.h"
 
 #include <jni.h>
 
+#include <array>
+
 namespace android {
 
 static jlong android_graphics_Picture_newPicture(JNIEnv* env, jobject, jlong srcHandle) {
@@ -91,20 +94,20 @@
     pict->endRecording();
 }
 
-static const JNINativeMethod gMethods[] = {
-    {"nativeGetWidth", "(J)I", (void*) android_graphics_Picture_getWidth},
-    {"nativeGetHeight", "(J)I", (void*) android_graphics_Picture_getHeight},
-    {"nativeConstructor", "(J)J", (void*) android_graphics_Picture_newPicture},
-    {"nativeCreateFromStream", "(Ljava/io/InputStream;[B)J", (void*)android_graphics_Picture_deserialize},
-    {"nativeBeginRecording", "(JII)J", (void*) android_graphics_Picture_beginRecording},
-    {"nativeEndRecording", "(J)V", (void*) android_graphics_Picture_endRecording},
-    {"nativeDraw", "(JJ)V", (void*) android_graphics_Picture_draw},
-    {"nativeWriteToStream", "(JLjava/io/OutputStream;[B)Z", (void*)android_graphics_Picture_serialize},
-    {"nativeDestructor","(J)V", (void*) android_graphics_Picture_killPicture}
+static const std::array gMethods = {
+    MAKE_JNI_NATIVE_METHOD("nativeGetWidth", "(J)I",  android_graphics_Picture_getWidth),
+    MAKE_JNI_NATIVE_METHOD("nativeGetHeight", "(J)I",  android_graphics_Picture_getHeight),
+    MAKE_JNI_NATIVE_METHOD("nativeConstructor", "(J)J",  android_graphics_Picture_newPicture),
+    MAKE_JNI_NATIVE_METHOD("nativeCreateFromStream", "(Ljava/io/InputStream;[B)J", android_graphics_Picture_deserialize),
+    MAKE_JNI_NATIVE_METHOD("nativeBeginRecording", "(JII)J",  android_graphics_Picture_beginRecording),
+    MAKE_JNI_NATIVE_METHOD("nativeEndRecording", "(J)V",  android_graphics_Picture_endRecording),
+    MAKE_JNI_NATIVE_METHOD("nativeDraw", "(JJ)V",  android_graphics_Picture_draw),
+    MAKE_JNI_NATIVE_METHOD("nativeWriteToStream", "(JLjava/io/OutputStream;[B)Z", android_graphics_Picture_serialize),
+    MAKE_JNI_NATIVE_METHOD("nativeDestructor","(J)V",  android_graphics_Picture_killPicture)
 };
 
 int register_android_graphics_Picture(JNIEnv* env) {
-    return RegisterMethodsOrDie(env, "android/graphics/Picture", gMethods, NELEM(gMethods));
+    return RegisterMethodsOrDie(env, "android/graphics/Picture", gMethods.data(), gMethods.size());
 }
 
 }; // namespace android
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index bf1cea8..891520a 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -276,20 +276,12 @@
     NativeInputChannel* nativeInputChannel =
         android_view_InputChannel_getNativeInputChannel(env, obj);
     if (nativeInputChannel) {
-        return javaObjectForIBinder(env, nativeInputChannel->getInputChannel()->getToken());
+        return javaObjectForIBinder(env,
+                nativeInputChannel->getInputChannel()->getConnectionToken());
     }
     return 0;
 }
 
-static void android_view_InputChannel_nativeSetToken(JNIEnv* env, jobject obj, jobject tokenObj) {
-    NativeInputChannel* nativeInputChannel =
-        android_view_InputChannel_getNativeInputChannel(env, obj);
-    sp<IBinder> token = ibinderForJavaObject(env, tokenObj);
-    if (nativeInputChannel != nullptr) {
-        nativeInputChannel->getInputChannel()->setToken(token);
-    }
-}
-
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gInputChannelMethods[] = {
@@ -312,8 +304,6 @@
             (void*)android_view_InputChannel_nativeDup },
     { "nativeGetToken", "()Landroid/os/IBinder;",
             (void*)android_view_InputChannel_nativeGetToken },
-    { "nativeSetToken", "(Landroid/os/IBinder;)V",
-            (void*)android_view_InputChannel_nativeSetToken }
 };
 
 int register_android_view_InputChannel(JNIEnv* env) {
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index bb57805..3704ccd 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -59,6 +59,10 @@
   return instance_;
 }
 
+static bool IsArtMemfd(const std::string& path) {
+  return android::base::StartsWith(path, "/memfd:/boot-image-methods.art");
+}
+
 bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const {
   // Check the static whitelist path.
   for (const auto& whitelist_path : kPathWhitelist) {
@@ -87,6 +91,11 @@
     return true;
   }
 
+  // the in-memory file created by ART through memfd_create is allowed.
+  if (IsArtMemfd(path)) {
+    return true;
+  }
+
   // Whitelist files needed for Runtime Resource Overlay, like these:
   // /system/vendor/overlay/framework-res.apk
   // /system/vendor/overlay-subdir/pg/framework-res.apk
@@ -312,6 +321,11 @@
     return DetachSocket(fail_fn);
   }
 
+  // Children can directly use the in-memory file created by ART through memfd_create.
+  if (IsArtMemfd(file_path)) {
+    return;
+  }
+
   // NOTE: This might happen if the file was unlinked after being opened.
   // It's a common pattern in the case of temporary files and the like but
   // we should not allow such usage from the zygote.
@@ -531,6 +545,10 @@
 }
 
 void FileDescriptorTable::RestatInternal(std::set<int>& open_fds, fail_fn_t fail_fn) {
+  // ART creates a file through memfd for optimization purposes. We make sure
+  // there is at most one being created.
+  bool art_memfd_seen = false;
+
   // Iterate through the list of file descriptors we've already recorded
   // and check whether :
   //
@@ -563,6 +581,14 @@
         // FD.
       }
 
+      if (IsArtMemfd(it->second->file_path)) {
+        if (art_memfd_seen) {
+          fail_fn("ART fd already seen: " + it->second->file_path);
+        } else {
+          art_memfd_seen = true;
+        }
+      }
+
       ++it;
 
       // Finally, remove the FD from the set of open_fds. We do this last because
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index 6ab0fc9..74ced89 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -3,8 +3,10 @@
 # Metrics
 joeo@google.com
 singhtejinder@google.com
+yanmin@google.com
 yaochen@google.com
 yro@google.com
+zhouwenjie@google.com
 
 # Settings UI
 per-file settings_enums.proto=tmfang@google.com
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 94be61f..97dae59 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2406,6 +2406,11 @@
     // CATEGORY: SETTINGS
     // OS: Q
     SETTINGS_AWARE_DISPLAY = 1750;
+
+    // OPEN: Settings > System > Input & Gesture > tap gesture
+    // CATEGORY: SETTINGS
+    // OS: Q
+    SETTINGS_GESTURE_TAP = 1751;
     // ---- End Q Constants, all Q constants go above this line ----
     // OPEN: Settings > Network & Internet > Wi-Fi > Click new network
     // CATEGORY: SETTINGS
@@ -2426,4 +2431,9 @@
     // and under gesture navigation mode.
     DIALOG_TOGGLE_SCREEN_MAGNIFICATION_GESTURE_NAVIGATION = 1802;
 
+    // OPEN: Settings > Security & screen lock -> Encryption & credentials > Install a certificate
+    // CATEGORY: SETTINGS
+    // OS: R
+    INSTALL_CERTIFICATE_FROM_STORAGE = 1803;
+
 }
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 7d0629e..898e2f0 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -42,6 +42,7 @@
 import "frameworks/base/core/proto/android/service/battery.proto";
 import "frameworks/base/core/proto/android/service/batterystats.proto";
 import "frameworks/base/core/proto/android/service/diskstats.proto";
+import "frameworks/base/core/proto/android/service/dropbox.proto";
 import "frameworks/base/core/proto/android/service/graphicsstats.proto";
 import "frameworks/base/core/proto/android/service/netstats.proto";
 import "frameworks/base/core/proto/android/service/notification.proto";
@@ -87,42 +88,80 @@
 
     optional android.util.LogProto main_logs = 1101 [
         (section).type = SECTION_LOG,
-        (section).args = "LOG_ID_MAIN"
+        (section).args = "main"
     ];
 
     optional android.util.LogProto radio_logs = 1102 [
         (section).type = SECTION_LOG,
-        (section).args = "LOG_ID_RADIO"
+        (section).args = "radio"
     ];
 
     optional android.util.LogProto events_logs = 1103 [
         (section).type = SECTION_LOG,
-        (section).args = "LOG_ID_EVENTS"
+        (section).args = "events"
     ];
 
     optional android.util.LogProto system_logs = 1104 [
         (section).type = SECTION_LOG,
-        (section).args = "LOG_ID_SYSTEM"
+        (section).args = "system"
     ];
 
     optional android.util.LogProto crash_logs = 1105 [
         (section).type = SECTION_LOG,
-        (section).args = "LOG_ID_CRASH"
+        (section).args = "crash"
     ];
 
     optional android.util.LogProto stats_logs = 1106 [
         (section).type = SECTION_LOG,
-        (section).args = "LOG_ID_STATS"
+        (section).args = "stats"
     ];
 
     optional android.util.LogProto security_logs = 1107 [
         (section).type = SECTION_LOG,
-        (section).args = "LOG_ID_SECURITY"
+        (section).args = "security"
     ];
 
     optional android.util.LogProto kernel_logs = 1108 [
         (section).type = SECTION_LOG,
-        (section).args = "LOG_ID_KERNEL"
+        (section).args = "kernel"
+    ];
+
+    // Last logcat sections.
+    // Note that kernel logs is not persisted since it's contained in last kmsg.
+    optional android.util.LogProto last_main_logs = 1109 [
+        (section).type = SECTION_LOG,
+        (section).args = "main -L"
+    ];
+
+    optional android.util.LogProto last_radio_logs = 1110 [
+        (section).type = SECTION_LOG,
+        (section).args = "radio -L"
+    ];
+
+    optional android.util.LogProto last_events_logs = 1111 [
+        (section).type = SECTION_LOG,
+        (section).args = "events -L"
+    ];
+
+    optional android.util.LogProto last_system_logs = 1112 [
+        (section).type = SECTION_LOG,
+        (section).args = "system -L"
+    ];
+
+    optional android.util.LogProto last_crash_logs = 1113 [
+        (section).type = SECTION_LOG,
+        (section).args = "crash -L"
+    ];
+
+    optional android.util.LogProto last_stats_logs = 1114 [
+        (section).type = SECTION_LOG,
+        (section).args = "stats -L"
+    ];
+
+    // security logs is only available with "Device Owner" mode
+    optional android.util.LogProto last_security_logs = 1115 [
+        (section).type = SECTION_LOG,
+        (section).args = "security -L"
     ];
 
     // Stack dumps
@@ -329,6 +368,22 @@
         (section).userdebug_and_eng_only = true
     ];
 
+    // Dropbox entries split by tags.
+    optional android.service.dropbox.DropBoxManagerServiceDumpProto dropbox_data_app_crashes = 3027 [
+        (section).type = SECTION_DUMPSYS,
+        (section).args = "dropbox --proto data_app_crash"
+    ];
+
+    optional android.service.dropbox.DropBoxManagerServiceDumpProto dropbox_data_app_anr = 3028 [
+        (section).type = SECTION_DUMPSYS,
+        (section).args = "dropbox --proto data_app_anr"
+    ];
+
+    optional android.service.dropbox.DropBoxManagerServiceDumpProto dropbox_data_app_native_crash = 3029 [
+        (section).type = SECTION_DUMPSYS,
+        (section).args = "dropbox --proto data_app_native_crash"
+    ];
+
     // Reserved for OEMs.
     extensions 50000 to 100000;
 }
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index f7d4b3f..31c19ca 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -281,6 +281,7 @@
         optional SettingProto force_rtl = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto emulate_display_cutout = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto force_desktop_mode_on_external_displays = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto enable_sizecompat_freeform = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional Development development = 39;
 
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index d01a45c..2f87deb 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -771,10 +771,11 @@
             option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
             optional string proc_name = 1;
-            optional string file = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
+            reserved 2; // file, DEST_EXPLICIT
             optional int32 pid = 3;
             optional int32 uid = 4;
             optional bool is_user_initiated = 5;
+            optional string uri = 6 [ (.android.privacy).dest = DEST_EXPLICIT ];
         }
         optional Dump dump = 2;
     }
diff --git a/core/proto/android/server/notificationhistory.proto b/core/proto/android/server/notificationhistory.proto
index 148bd7e..1e6ee3f 100644
--- a/core/proto/android/server/notificationhistory.proto
+++ b/core/proto/android/server/notificationhistory.proto
@@ -46,7 +46,7 @@
 
     // The uid of the package that posted the notification
     optional int32 uid = 7;
-    // The user id of the package that posted the notification
+    // The user id that the notification was posted to
     optional int32 user_id = 8;
     // The time at which the notification was posted
     optional int64 posted_time_ms = 9;
@@ -71,19 +71,19 @@
       optional ImageTypeEnum image_type = 1;
       optional string image_bitmap_filename = 2;
       optional int32 image_resource_id = 3;
-      optional bytes image_data = 4;
-      optional string image_uri = 5;
+      optional string image_resource_id_package = 4;
+      optional bytes image_data = 5;
+      optional int32 image_data_length = 6;
+      optional int32 image_data_offset = 7;
+      optional string image_uri = 8;
     }
   }
 
-  // The time the last entry was written
-  optional int64 end_time_ms = 1;
   // Pool of strings to save space
-  optional StringPool stringpool = 2;
+  optional StringPool string_pool = 1;
   // Versioning fields
-  optional int32 major_version = 3;
-  optional int32 minor_version = 4;
+  optional int32 major_version = 2;
 
   // List of historical notifications
-  repeated Notification notification = 5;
+  repeated Notification notification = 3;
 }
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index fd10503..69e67d1 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -216,7 +216,8 @@
     optional bool fills_parent = 4;
     optional .android.graphics.RectProto bounds = 5;
     optional .android.graphics.RectProto displayed_bounds = 6;
-    optional bool defer_removal = 7;
+    // Will be removed soon.
+    optional bool defer_removal = 7 [deprecated=true];
     optional int32 surface_width = 8;
     optional int32 surface_height = 9;
 }
@@ -230,7 +231,7 @@
     optional WindowTokenProto window_token = 2;
     optional bool last_surface_showing = 3;
     optional bool is_waiting_for_transition_start = 4;
-    optional bool is_really_animating = 5;
+    optional bool is_animating = 5;
     optional AppWindowThumbnailProto thumbnail = 6;
     optional bool fills_parent = 7;
     optional bool app_stopped = 8;
diff --git a/core/proto/android/service/dropbox.proto b/core/proto/android/service/dropbox.proto
new file mode 100644
index 0000000..29fe62b
--- /dev/null
+++ b/core/proto/android/service/dropbox.proto
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.service.dropbox;
+
+import "frameworks/base/core/proto/android/privacy.proto";
+
+option java_multiple_files = true;
+
+// Dump from com.android.server.DropboxManagerService.java.
+message DropBoxManagerServiceDumpProto {
+    option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+    message Entry {
+        // Time when entry was originally created.
+        optional int64 time_ms = 1 [ (.android.privacy).dest = DEST_AUTOMATIC ] ;
+        optional bytes data = 2;
+    }
+    repeated Entry entries = 1;
+}
diff --git a/core/proto/android/service/usb.proto b/core/proto/android/service/usb.proto
index 2e1de79..40c5a85 100644
--- a/core/proto/android/service/usb.proto
+++ b/core/proto/android/service/usb.proto
@@ -32,6 +32,7 @@
     optional UsbPortManagerProto port_manager = 3;
     optional UsbAlsaManagerProto alsa_manager = 4;
     optional UsbSettingsManagerProto settings_manager = 5;
+    optional UsbPermissionsManagerProto permissions_manager = 6;
 }
 
 message UsbDeviceManagerProto {
@@ -309,26 +310,12 @@
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
     optional int32 user_id = 1;
-    repeated UsbSettingsDevicePermissionProto device_permissions = 2;
-    repeated UsbSettingsAccessoryPermissionProto accessory_permissions = 3;
+    reserved 2; // previously device_permissions, now unused
+    reserved 3; // previously accessory_permissions, now unused
     repeated UsbDeviceAttachedActivities device_attached_activities = 4;
     repeated UsbAccessoryAttachedActivities accessory_attached_activities = 5;
 }
 
-message UsbSettingsDevicePermissionProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional string device_name = 1;
-    repeated int32 uids = 2;
-}
-
-message UsbSettingsAccessoryPermissionProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
-
-    optional string accessory_description = 1;
-    repeated int32 uids = 2;
-}
-
 message UsbProfileGroupSettingsManagerProto {
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
@@ -345,6 +332,63 @@
     optional UserPackageProto user_package = 2;
 }
 
+message UsbPermissionsManagerProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    repeated UsbUserPermissionsManagerProto user_permissions = 1;
+}
+
+message UsbUserPermissionsManagerProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional int32 user_id = 1;
+
+    repeated UsbDevicePermissionProto device_permissions = 2;
+    repeated UsbAccessoryPermissionProto accessory_permissions = 3;
+
+    repeated UsbDevicePersistentPermissionProto device_persistent_permissions = 4;
+    repeated UsbAccessoryPersistentPermissionProto accessory_persistent_permissions = 5;
+}
+
+message UsbDevicePermissionProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    // Name of device set by manufacturer
+    // All devices of the same model have the same name
+    optional string device_name = 1;
+    repeated int32 uids = 2;
+}
+
+message UsbAccessoryPermissionProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    // Description of accessory set by manufacturer
+    // All accessories of the same model have the same description
+    optional string accessory_description = 1;
+    repeated int32 uids = 2;
+}
+
+message UsbDevicePersistentPermissionProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional UsbDeviceFilterProto device_filter = 1;
+    repeated UsbUidPermissionProto permission_values = 2;
+}
+
+message UsbAccessoryPersistentPermissionProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional UsbAccessoryFilterProto accessory_filter = 1;
+    repeated UsbUidPermissionProto permission_values = 2;
+}
+
+message UsbUidPermissionProto {
+    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    optional int32 uid = 1;
+    optional bool is_granted = 2;
+}
+
 message UsbDeviceFilterProto {
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c365aae..66e84dc 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -497,6 +497,7 @@
     <protected-broadcast android:name="android.telephony.action.CARRIER_CONFIG_CHANGED" />
     <protected-broadcast android:name="android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED" />
     <protected-broadcast android:name="android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED" />
+    <protected-broadcast android:name="android.telephony.action.OTA_EMERGENCY_NUMBER_DB_INSTALLED" />
     <protected-broadcast android:name="android.telephony.action.SECRET_CODE" />
     <protected-broadcast android:name="android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION" />
     <protected-broadcast android:name="android.telephony.action.SUBSCRIPTION_PLANS_CHANGED" />
@@ -2005,6 +2006,11 @@
     <!-- =========================================== -->
     <eat-comment />
 
+    <!-- @SystemApi Allows granting runtime permissions to telephony related components.
+         @hide Used internally. -->
+    <permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS"
+        android:protectionLevel="signature|telephony" />
+
     <!-- Allows modification of the telephony state - power on, mmi, etc.
          Does not include placing calls.
          <p>Not for use by third-party applications. -->
@@ -4511,9 +4517,9 @@
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to turn on / off quiet mode.
-         @hide <p>Not for use by third-party applications. -->
+         @hide -->
     <permission android:name="android.permission.MODIFY_QUIET_MODE"
-                android:protectionLevel="signature|privileged" />
+                android:protectionLevel="signature|privileged|wellbeing" />
 
     <!-- Allows internal management of the camera framework
          @hide -->
@@ -4647,6 +4653,13 @@
                 android:protectionLevel="normal" />
     <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
 
+    <!-- @hide Allow the caller to collect debugging data from processes that otherwise
+        would require USAGE_STATS. Before sharing this data with other apps, holders
+        of this permission are REQUIRED to themselves check that the caller has
+        PACKAGE_USAGE_STATS and OP_GET_USAGE_STATS. -->
+    <permission android:name="android.permission.PEEK_DROPBOX_DATA"
+        android:protectionLevel="signature|privileged" />
+
     <application android:process="system"
                  android:persistent="true"
                  android:hasCode="false"
@@ -4728,19 +4741,6 @@
                 android:excludeFromRecents="true"
                 android:process=":ui">
         </activity>
-        <activity android:name="com.android.internal.app.DumpHeapActivity"
-                android:theme="@style/Theme.Translucent.NoTitleBar"
-                android:label="@string/dump_heap_title"
-                android:finishOnCloseSystemDialogs="true"
-                android:noHistory="true"
-                android:excludeFromRecents="true"
-                android:process=":ui">
-        </activity>
-        <provider android:name="com.android.server.am.DumpHeapProvider"
-                android:authorities="com.android.server.heapdump"
-                android:grantUriPermissions="true"
-                android:multiprocess="false"
-                android:singleUser="true" />
 
         <activity android:name="android.accounts.ChooseAccountActivity"
                 android:excludeFromRecents="true"
diff --git a/core/res/res/layout/resolve_list_item.xml b/core/res/res/layout/resolve_list_item.xml
index 4857095..86f028c 100644
--- a/core/res/res/layout/resolve_list_item.xml
+++ b/core/res/res/layout/resolve_list_item.xml
@@ -54,7 +54,9 @@
                   android:minLines="1"
                   android:maxLines="1"
                   android:ellipsize="marquee" />
-        <!-- Extended activity info to distinguish between duplicate activity names -->
+        <!-- Extended activity info to distinguish between duplicate activity names
+            or provide record w/o permission warnings.
+        -->
         <TextView android:id="@android:id/text2"
                   android:textColor="?android:attr/textColorSecondary"
                   android:fontFamily="@android:string/config_bodyFontFamily"
@@ -64,7 +66,7 @@
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:minLines="1"
-                  android:maxLines="1"
+                  android:maxLines="2"
                   android:ellipsize="marquee" />
     </LinearLayout>
 </LinearLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 4ca0df4..7f72a13 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> het geen internettoegang nie"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tik vir opsies"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Selnetwerk het nie internettoegang nie"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Netwerk het nie internettoegang nie"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Daar kan nie by private DNS-bediener ingegaan word nie"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Gekoppel"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> het beperkte konnektiwiteit"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Tik om in elk geval te koppel"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Stoor"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Nee, dankie"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Dateer op"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Gaan voort"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"wagwoord"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"adres"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kredietkaart"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"debietkaart"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"betaalkaart"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"kaart"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"gebruikernaam"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"e-posadres"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Bly kalm en soek skuiling naby."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index eb5265e..f576d04 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ምንም የበይነ መረብ መዳረሻ የለም"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ለአማራጮች መታ ያድርጉ"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"የተንቀሳቃሽ ስልክ አውታረ መረብ የበይነመረብ መዳረሻ የለውም"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"አውታረ መረብ የበይነመረብ መዳረሻ የለውም"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"የግል ዲኤንኤስ አገልጋይ ሊደረስበት አይችልም"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"ተገናኝቷል"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> የተገደበ ግንኙነት አለው"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"ለማንኛውም ለማገናኘት መታ ያድርጉ"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"አስቀምጥ"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"አይ፣ አመሰግናለሁ"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"አዘምን"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"ቀጥል"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"የይለፍ ቃል"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"አድራሻ"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ክሬዲት ካርድ"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"ዴቢት ካርድ"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"የክፍያ ካርድ"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"ካርድ"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"የተጠቃሚ ስም"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"የኢሜይል አድራሻ"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"ረጋ ይበሉና በአቅራቢያ ያለ መጠለያ ይፈልጉ።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index c9067e5..7974a08 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1362,6 +1362,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"لا يتوفّر في <xliff:g id="NETWORK_SSID">%1$s</xliff:g> إمكانية الاتصال بالإنترنت."</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"انقر للحصول على الخيارات."</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"شبكة الجوّال هذه غير متصلة بالإنترنت"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"الشبكة غير متصلة بالإنترنت"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"لا يمكن الوصول إلى خادم أسماء نظام نطاقات خاص"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"تمّ الاتصال."</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"إمكانية اتصال <xliff:g id="NETWORK_SSID">%1$s</xliff:g> محدودة."</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"يمكنك النقر للاتصال على أي حال."</string>
@@ -2101,9 +2104,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"حفظ"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"لا، شكرًا"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"تعديل"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"متابعة"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"كلمة مرور"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"عنوان"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"بطاقة ائتمان"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"بطاقة السحب الآلي"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"بطاقة الدفع"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"بطاقة"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"اسم المستخدم"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"عنوان البريد الإلكتروني"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"يُرجى الثبات والبحث عن ملاذ بالجوار."</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 7a89b65..8558d7c 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ৰ ইণ্টাৰনেটৰ এক্সেছ নাই"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"অধিক বিকল্পৰ বাবে টিপক"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"ম’বাইল নেটৱৰ্কৰ কোনো ইণ্টাৰনেটৰ এক্সেছ নাই"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"নেটৱৰ্কৰ কোনো ইণ্টাৰনেটৰ এক্সেছ নাই"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"ব্যক্তিগত DNS ছাৰ্ভাৰ এক্সেছ কৰিব নোৱাৰি"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"সংযোগ কৰা হ’ল"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ৰ সকলো সেৱাৰ এক্সেছ নাই"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"যিকোনো প্ৰকাৰে সংযোগ কৰিবলৈ টিপক"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"ছেভ কৰক"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"নালাগে, ধন্যবাদ"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"আপডে’ট কৰক"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"অব্যাহত ৰাখক"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"পাছৱৰ্ড"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"ঠিকনা"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ক্ৰেডিট কাৰ্ড"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"ডেবিট কাৰ্ড"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"পৰিশোধৰ বাবে ব্যৱহাৰ কৰা কার্ড"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"কাৰ্ড"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"ব্যৱহাৰকাৰীৰ নাম"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"ইমেইল ঠিকনা"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"শান্ত হৈ থাকক আৰু ওচৰৰ ক\'ৰবাত আশ্ৰয় বিচাৰক।"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 21dbf03..5b135cf 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> üçün internet girişi əlçatan deyil"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Seçimlər üçün tıklayın"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobil şəbəkənin internetə girişi yoxdur"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Şəbəkənin internetə girişi yoxdur"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Özəl DNS serverinə giriş mümkün deyil"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Qoşuldu"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> bağlantını məhdudlaşdırdı"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"İstənilən halda klikləyin"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Yadda saxlayın"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Xeyr, çox sağ olun"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Yeniləyin"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Davam edin"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"parol"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"ünvan"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kredit kartı"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"debet kart"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"ödəniş kartı"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"kart"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"istifadəçi adı"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"e-poçt ünvanı"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Sakit qalın və yaxınlıqda sığınacaq axtarın."</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index dbb788d..02b098f 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1296,6 +1296,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nema pristup internetu"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dodirnite za opcije"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobilna mreža nema pristup internetu"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Mreža nema pristup internetu"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Pristup privatnom DNS serveru nije uspeo"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Povezano je"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ima ograničenu vezu"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Dodirnite da biste se ipak povezali"</string>
@@ -1996,9 +1999,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Sačuvaj"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Ne, hvala"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Ažuriraj"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Nastavi"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"lozinka"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"adresa"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kreditna kartica"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"debitna kartica"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"platna kartica"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"kartica"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"korisničko ime"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"imejl adresa"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Ostanite mirni i potražite sklonište u okolini."</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index bae2640..4060ed7 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1318,6 +1318,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> не мае доступу ў інтэрнэт"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Дакраніцеся, каб убачыць параметры"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Мабільная сетка не мае доступу ў інтэрнэт"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Сетка не мае доступу ў інтэрнэт"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Не ўдалося атрымаць доступ да прыватнага DNS-сервера"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Падключана"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> мае абмежаваную магчымасць падключэння"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Націсніце, каб падключыцца"</string>
@@ -2031,9 +2034,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Захаваць"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Не, дзякуй"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Абнавіць"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Працягнуць"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"пароль"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"адрас"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"крэдытная картка"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"дэбетовая картка"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"плацежная картка"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"картка"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"карыстальнік"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"адрас электроннай пошты"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Заставайцеся спакойнымі і пашукайце прытулак паблізу."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index e7b3090..b0cea11 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> няма достъп до интернет"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Докоснете за опции"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Мобилната мрежа няма достъп до интернет"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Мрежата няма достъп до интернет"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Не може да се осъществи достъп до частния DNS сървър"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Установена е връзка"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> има ограничена свързаност"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Докоснете, за да се свържете въпреки това"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Запазване"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Не, благодаря"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Актуализиране"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Напред"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"Паролата"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"Адресът"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"Кредитната карта"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"дебитна карта"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"карта за плащане"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"карта"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"потребителско име"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"имейл адрес"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Запазете спокойствие и потърсете убежище в района."</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index beb08b2..514a6ce 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-এর ইন্টারনেটে অ্যাক্সেস নেই"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"বিকল্পগুলির জন্য আলতো চাপুন"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"মোবাইল নেটওয়ার্কে কোনও ইন্টারনেট অ্যাক্সেস নেই"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"নেটওয়ার্কে কোনও ইন্টারনেট অ্যাক্সেস নেই"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"ব্যক্তিগত ডিএনএস সার্ভার অ্যাক্সেস করা যাবে না"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"কানেক্ট করা হয়েছে"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-এর সীমিত কানেক্টিভিটি আছে"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"তবুও কানেক্ট করতে ট্যাপ করুন"</string>
@@ -1962,9 +1965,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"সেভ করুন"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"না থাক"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"আপডেট করুন"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"চালিয়ে যান"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"পাসওয়ার্ড"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"ঠিকানা"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ক্রেডিট কার্ড"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"ডেবিট কার্ড"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"পেমেন্টের কার্ড"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"কার্ড"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"ইউজারনেম"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"ইমেল ঠিকানা"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"শান্ত থাকুন, আশেপাশে আশ্রয় খুঁজুন।"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 862beee..1ddc0e2 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1298,6 +1298,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"Mreža <xliff:g id="NETWORK_SSID">%1$s</xliff:g> nema pristup internetu"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dodirnite za opcije"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobilna mreža nema pristup internetu"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Mreža nema pristup internetu"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Nije moguće pristupiti privatnom DNS serveru"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Povezano"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Mreža <xliff:g id="NETWORK_SSID">%1$s</xliff:g> ima ograničenu povezivost"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Dodirnite da se ipak povežete"</string>
@@ -1998,9 +2001,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Sačuvaj"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Ne, hvala"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Ažuriraj"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Nastavi"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"lozinka"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"adresa"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kreditna kartica"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"debitna kartica"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"kartica za plaćanje"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"kartica"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"korisničko ime"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"adresa e-pošte"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Ostanite smireni i potražite sklonište u blizini."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 28b9a16..fe7f87c 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -532,21 +532,21 @@
     <string name="biometric_not_recognized" msgid="5770511773560736082">"No s\'ha reconegut"</string>
     <string name="biometric_error_canceled" msgid="349665227864885880">"S\'ha cancel·lat l\'autenticació"</string>
     <string name="biometric_error_device_not_secured" msgid="6583143098363528349">"No s\'ha establert cap PIN, patró o contrasenya"</string>
-    <string name="fingerprint_acquired_partial" msgid="735082772341716043">"S\'ha detectat una empremta dactilar parcial. Torna-ho a provar."</string>
-    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"No s\'ha pogut processar l\'empremta dactilar. Torna-ho a provar."</string>
+    <string name="fingerprint_acquired_partial" msgid="735082772341716043">"S\'ha detectat una empremta digital parcial. Torna-ho a provar."</string>
+    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"No s\'ha pogut processar l\'empremta digital. Torna-ho a provar."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"El sensor d\'empremtes dactilars està brut. Neteja\'l i torna-ho a provar."</string>
     <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"El dit s\'ha mogut massa ràpid. Torna-ho a provar."</string>
     <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"El dit s\'ha mogut massa lentament. Torna-ho a provar."</string>
   <string-array name="fingerprint_acquired_vendor">
   </string-array>
-    <string name="fingerprint_authenticated" msgid="5309333983002526448">"L\'empremta dactilar s\'ha autenticat"</string>
+    <string name="fingerprint_authenticated" msgid="5309333983002526448">"L\'empremta digital s\'ha autenticat"</string>
     <string name="face_authenticated_no_confirmation_required" msgid="4018680978348659031">"Cara autenticada"</string>
     <string name="face_authenticated_confirmation_required" msgid="8778347003507633610">"Cara autenticada; prem el botó per confirmar"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"El maquinari per a empremtes dactilars no està disponible."</string>
-    <string name="fingerprint_error_no_space" msgid="1055819001126053318">"L\'empremta dactilar no es pot desar. Suprimeix-ne una."</string>
-    <string name="fingerprint_error_timeout" msgid="3927186043737732875">"S\'ha esgotat el temps d\'espera per a l\'empremta dactilar. Torna-ho a provar."</string>
-    <string name="fingerprint_error_canceled" msgid="4402024612660774395">"S\'ha cancel·lat l\'operació d\'empremta dactilar."</string>
-    <string name="fingerprint_error_user_canceled" msgid="7999639584615291494">"L\'usuari ha cancel·lat l\'operació d\'empremta dactilar."</string>
+    <string name="fingerprint_error_no_space" msgid="1055819001126053318">"L\'empremta digital no es pot desar. Suprimeix-ne una."</string>
+    <string name="fingerprint_error_timeout" msgid="3927186043737732875">"S\'ha esgotat el temps d\'espera per a l\'empremta digital. Torna-ho a provar."</string>
+    <string name="fingerprint_error_canceled" msgid="4402024612660774395">"S\'ha cancel·lat l\'operació d\'empremta digital."</string>
+    <string name="fingerprint_error_user_canceled" msgid="7999639584615291494">"L\'usuari ha cancel·lat l\'operació d\'empremta digital."</string>
     <string name="fingerprint_error_lockout" msgid="5536934748136933450">"S\'han produït massa intents. Torna-ho a provar més tard."</string>
     <string name="fingerprint_error_lockout_permanent" msgid="5033251797919508137">"S\'han fet massa intents. S\'ha desactivat el sensor d\'empremtes dactilars."</string>
     <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Torna-ho a provar."</string>
@@ -555,7 +555,7 @@
     <string name="fingerprint_name_template" msgid="5870957565512716938">"Dit <xliff:g id="FINGERID">%d</xliff:g>"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
-    <string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Icona d\'empremta dactilar"</string>
+    <string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Icona d\'empremta digital"</string>
     <string name="permlab_manageFace" msgid="7262837876352591553">"gestiona el maquinari de desbloqueig facial"</string>
     <string name="permdesc_manageFace" msgid="8919637120670185330">"Permet que l\'aplicació afegeixi i suprimeixi plantilles de cares que es puguin fer servir."</string>
     <string name="permlab_useFaceAuthentication" msgid="2565716575739037572">"utilitza el maquinari de desbloqueig facial"</string>
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> no té accés a Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toca per veure les opcions"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"La xarxa mòbil no té accés a Internet"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"La xarxa no té accés a Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"No es pot accedir al servidor DNS privat"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Connectat"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> té una connectivitat limitada"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Toca per connectar igualment"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Desa"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"No, gràcies"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Actualitza"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Continua"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"contrasenya"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"adreça"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"targeta de crèdit"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"targeta de dèbit"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"targeta de pagament"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"targeta"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"nom d\'usuari"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"adreça electrònica"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Mantén la calma i busca refugi a prop."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 8ba6f34..b684193 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1318,6 +1318,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"Síť <xliff:g id="NETWORK_SSID">%1$s</xliff:g> nemá přístup k internetu"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Klepnutím zobrazíte možnosti"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobilní síť nemá přístup k internetu"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Síť nemá přístup k internetu"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Nelze získat přístup k soukromému serveru DNS"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Připojeno"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Síť <xliff:g id="NETWORK_SSID">%1$s</xliff:g> umožňuje jen omezené připojení"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Klepnutím se i přesto připojíte"</string>
@@ -2031,9 +2034,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Uložit"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Ne, děkuji"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Aktualizovat"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Pokračovat"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"heslo"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"adresa"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"platební karta"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"debetní karta"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"platební karta"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"karta"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"uživatelské jméno"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"e-mailová adresa"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Zachovejte klid a přesuňte se na bezpečné místo v okolí."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 0d40688..22f1e5d 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har ingen internetforbindelse"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tryk for at se valgmuligheder"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobilnetværket har ingen internetadgang"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Netværket har ingen internetadgang"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Der er ikke adgang til den private DNS-server"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Der er oprettet forbindelse"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har begrænset forbindelse"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Tryk for at oprette forbindelse alligevel"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Gem"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Nej tak"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Opdater"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Fortsæt"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"adgangskode"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"adresse"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kreditkort"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"betalingskort"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"betalingskort"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"kort"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"brugernavn"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"mailadresse"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Bevar roen, og søg ly i nærheden."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index f051345..b74cd7e 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> hat keinen Internetzugriff"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Für Optionen tippen"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobiles Netzwerk hat keinen Internetzugriff"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Netzwerk hat keinen Internetzugriff"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Auf den privaten DNS-Server kann nicht zugegriffen werden"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Verbunden"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Schlechte Verbindung mit <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Tippen, um die Verbindung trotzdem herzustellen"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Speichern"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Nein danke"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Aktualisieren"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Fortsetzen"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"Passwort"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"Adresse"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"Kreditkarte"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"Debitkarte"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"Zahlungskarte"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"Karte"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"Nutzername"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"E-Mail-Adresse"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Bleibe ruhig und suche in der Nähe Schutz."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index a360de0..e74cbb1 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -299,13 +299,13 @@
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Μικρόφωνο"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ηχογραφεί"</string>
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η εγγραφή ήχου;"</string>
-    <string name="permgrouplab_activityRecognition" msgid="1565108047054378642">"Σωματική δραστηριότητα"</string>
+    <string name="permgrouplab_activityRecognition" msgid="1565108047054378642">"Σωματική δραστ/τητα"</string>
     <string name="permgroupdesc_activityRecognition" msgid="6949472038320473478">"πρόσβαση στη σωματική σας δραστηριότητα"</string>
     <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; να έχει πρόσβαση στη σωματική σας δραστηριότητα;"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Κάμερα"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"γίνεται λήψη φωτογραφιών και εγγραφή βίντεο"</string>
     <string name="permgrouprequest_camera" msgid="1299833592069671756">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; η λήψη φωτογραφιών και η εγγραφή βίντεο;"</string>
-    <string name="permgrouplab_calllog" msgid="8798646184930388160">"Αρχεία καταγραφής κλήσεων"</string>
+    <string name="permgrouplab_calllog" msgid="8798646184930388160">"Αρχεία καταγρ. κλήσ."</string>
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"ανάγνωση και εγγραφή αρχείου καταγραφής τηλεφωνικών κλήσεων"</string>
     <string name="permgrouprequest_calllog" msgid="8487355309583773267">"Να επιτρέπεται στην εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; να έχει πρόσβαση στα αρχεία καταγραφής τηλεφωνικών κλήσεών σας;"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"Τηλέφωνο"</string>
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"Η εφαρμογή <xliff:g id="NETWORK_SSID">%1$s</xliff:g> δεν έχει πρόσβαση στο διαδίκτυο"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Πατήστε για να δείτε τις επιλογές"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Το δίκτυο κινητής τηλεφωνίας δεν έχει πρόσβαση στο διαδίκτυο."</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Το δίκτυο δεν έχει πρόσβαση στο διαδίκτυο."</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Δεν είναι δυνατή η πρόσβαση στον ιδιωτικό διακομιστή DNS."</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Συνδέθηκε"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Το δίκτυο <xliff:g id="NETWORK_SSID">%1$s</xliff:g> έχει περιορισμένη συνδεσιμότητα"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Πατήστε για σύνδεση ούτως ή άλλως"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Αποθήκευση"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Όχι, ευχαριστώ"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Ενημέρωση"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Συνέχεια"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"κωδικός πρόσβασης"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"διεύθυνση"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"πιστωτική κάρτα"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"χρεωστική κάρτα"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"κάρτα πληρωμής"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"κάρτα"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"όνομα χρήστη"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"διεύθυνση email"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Μείνετε ψύχραιμοι και αναζητήστε κάποιο κοντινό καταφύγιο."</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 1e0e93a..88fb0fd 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no Internet access"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobile network has no Internet access"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Network has no Internet access"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Private DNS server cannot be accessed"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Connected"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Tap to connect anyway"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Save"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"No, thanks"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Update"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Continue"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"password"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"address"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"credit card"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"debit card"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"payment card"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"card"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"username"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"email address"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Stay calm and seek shelter nearby."</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 4deaf2e..8a1c2c4 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no Internet access"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobile network has no Internet access"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Network has no Internet access"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Private DNS server cannot be accessed"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Connected"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Tap to connect anyway"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Save"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"No, thanks"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Update"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Continue"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"password"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"address"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"credit card"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"debit card"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"payment card"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"card"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"username"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"email address"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Stay calm and seek shelter nearby."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 1e0e93a..88fb0fd 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no Internet access"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobile network has no Internet access"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Network has no Internet access"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Private DNS server cannot be accessed"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Connected"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Tap to connect anyway"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Save"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"No, thanks"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Update"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Continue"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"password"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"address"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"credit card"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"debit card"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"payment card"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"card"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"username"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"email address"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Stay calm and seek shelter nearby."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 1e0e93a..88fb0fd 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no Internet access"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tap for options"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobile network has no Internet access"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Network has no Internet access"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Private DNS server cannot be accessed"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Connected"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Tap to connect anyway"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Save"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"No, thanks"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Update"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Continue"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"password"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"address"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"credit card"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"debit card"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"payment card"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"card"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"username"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"email address"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Stay calm and seek shelter nearby."</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 5fe1bb1..fbb1cc7 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‏‎‎‎‏‏‎‏‎‏‏‏‎‎‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‏‎‏‏‏‏‎‎‏‎‎‏‎‏‎‎‎‏‎‎‏‎‎‏‏‎<xliff:g id="NETWORK_SSID">%1$s</xliff:g>‎‏‎‎‏‏‏‎ has no internet access‎‏‎‎‏‎"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‏‏‎‎‏‏‎‏‏‏‎‏‏‎‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‎‎‎‏‎‎‎‏‏‎‏‎‏‏‎‏‎Tap for options‎‏‎‎‏‎"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‏‏‎‎‏‏‎‏‎‎‏‏‎‎‎‏‎‏‎‎‎‏‎‏‎‏‏‏‎‎‎‎‎‎‏‎‏‎‎‎‏‎‏‏‎‏‎‎‏‎‏‎Mobile network has no internet access‎‏‎‎‏‎"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‎‏‏‏‎‏‎‎‏‎‎‎‎‏‎‏‏‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‎‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‏‎Network has no internet access‎‏‎‎‏‎"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‏‎‏‎‏‎‎‎‏‎‎‎‎‏‎‏‏‎‎‏‎‎‏‎‎‎‎‎‎‏‎‏‏‎‏‏‎‎‎‎‏‏‎‏‏‏‏‎‏‏‎‏‎‎Private DNS server cannot be accessed‎‏‎‎‏‎"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‎‎‎‎‎‏‏‎‏‏‎‏‎‏‎‎‏‎‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‏‎‏‎‎‎‎‎‎‎‏‎‎‏‎‏‎‏‎Connected‎‏‎‎‏‎"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‎‎‏‎‏‏‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‎‎‎‎‎‎‏‏‏‎‏‎‎‏‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="NETWORK_SSID">%1$s</xliff:g>‎‏‎‎‏‏‏‎ has limited connectivity‎‏‎‎‏‎"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‎‎‏‏‎‎‏‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‎‏‎‏‏‎‏‎‎‎‎‏‎Tap to connect anyway‎‏‎‎‏‎"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‏‎‏‎‏‏‎‏‎‏‎‏‏‎‎‏‎‏‏‏‎‏‏‏‏‎‎‎‏‎‎‏‎‎‎‏‎‏‏‎‎‎‎‏‎Save‎‏‎‎‏‎"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‏‎‏‏‏‎‎‏‎‏‎‏‏‏‏‏‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‏‎‎‎‎‎‏‏‏‎‏‎‎‏‏‏‏‎‏‏‎‏‏‎No thanks‎‏‎‎‏‎"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‏‎‏‎‎‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎‏‎‎‎‎‎‎‎‏‏‎‏‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‏‏‎‎Update‎‏‎‎‏‎"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‏‎‏‏‏‎‏‏‏‎‏‎‏‎‎‎‎‏‏‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‏‎‏‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎Continue‎‏‎‎‏‎"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‏‏‎‎‏‎‎‎‏‎‏‏‎‎‎‎‏‎‎‎‏‎‏‏‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‏‎‏‏‏‎‎‎‎‎password‎‏‎‎‏‎"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‎‎‏‎‏‎‏‏‎‏‎‏‏‎‎‎‏‏‎‏‏‏‎‎‏‏‎‏‎‏‏‎‏‏‎‏‏‎‎‎‏‎‏‏‏‎‎‎‎‏‏‎‎address‎‏‎‎‏‎"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎‎‏‎‏‎‎‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‎‏‏‏‎‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‎credit card‎‏‎‎‏‎"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‏‎‎‎‏‎‎‎‎‏‏‎‎‎‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‏‎‎‎‎‏‏‎‏‏‏‎‎‎‎‎‏‏‏‎‏‎debit card‎‏‎‎‏‎"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‎‎‏‏‎‎‏‎‏‏‎‎‎‎‎‏‎‏‎‎‏‎‏‏‏‏‎‏‎‎‏‎‎‏‏‏‏‏‎‎‏‎‏‏‏‏‎‏‏‎‎‏‎‎‎‏‎payment card‎‏‎‎‏‎"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‎‏‏‎‎‏‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎card‎‏‎‎‏‎"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‏‎‏‎‎‎‏‎‎‏‏‏‏‏‎‎‎‎‏‏‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‎‎‎‏‏‏‎‏‎‏‎‏‏‎‏‏‎‏‎‎username‎‏‎‎‏‎"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎‎‏‏‎‎‎‎‏‏‎‏‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‏‏‏‏‎‎email address‎‏‎‎‏‎"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‎‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎‎‏‏‎‏‏‏‎‏‎‏‎‏‏‎‎‎‏‎‎‏‎‏‏‎‏‏‏‎‎‎‏‎‏‎‎‏‎Stay calm and seek shelter nearby.‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index feb4aee..7fe219e 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>no tiene acceso a Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Presiona para ver opciones"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"La red móvil no tiene acceso a Internet"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"La red no tiene acceso a Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"No se puede acceder al servidor DNS privado"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Se estableció conexión"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tiene conectividad limitada"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Presiona para conectarte de todas formas"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Guardar"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"No, gracias"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Actualizar"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Continuar"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"contraseña"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"dirección"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"tarjeta de crédito"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"tarjeta de débito"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"tarjeta de pago"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"tarjeta"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"nombre de usuario"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"dirección de correo electrónico"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Mantén la calma y busca un refugio cercano."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 75510b3..35e2c38 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> no tiene acceso a Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toca para ver opciones"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"La red móvil no tiene acceso a Internet"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"La red no tiene acceso a Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"No se ha podido acceder al servidor DNS privado"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Conectado"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tiene una conectividad limitada"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Toca para conectarte de todas formas"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Guardar"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"No, gracias"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Actualizar"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Continuar"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"contraseña"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"dirección"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"tarjeta de crédito"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"tarjeta de débito"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"tarjeta de pago"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"tarjeta"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"nombre de usuario"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"dirección de correo electrónico"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Mantén la calma y busca refugio en algún lugar cercano."</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 0e7befd..a8f546d 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"Võrgul <xliff:g id="NETWORK_SSID">%1$s</xliff:g> puudub Interneti-ühendus"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Puudutage valikute nägemiseks"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobiilsidevõrgul puudub Interneti-ühendus"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Võrgul puudub Interneti-ühendus"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Privaatsele DNS-serverile ei pääse juurde"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Ühendatud"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Võrgu <xliff:g id="NETWORK_SSID">%1$s</xliff:g> ühendus on piiratud"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Puudutage, kui soovite siiski ühenduse luua"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Salvesta"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Tänan, ei"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Värskenda"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Jätka"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"parool"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"aadress"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"krediitkaart"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"deebetkaart"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"maksekaart"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"kaart"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"kasutajanimi"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"e-posti aadress"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Jääge rahulikuks ja otsige lähedusest peavarju."</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 22391dc..d87bdfb 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -861,7 +861,7 @@
     <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Eredua ahaztu zaizu?"</string>
     <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Kontua desblokeatzea"</string>
     <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Eredua marrazteko saiakera gehiegi egin dira"</string>
-    <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Desblokeatzeko, hasi saioa Google kontuarekin."</string>
+    <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Desblokeatzeko, hasi saioa Google-ko kontuarekin."</string>
     <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Erabiltzaile-izena (helbide elektronikoa)"</string>
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Pasahitza"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Hasi saioa"</string>
@@ -1133,7 +1133,7 @@
     <string name="whichApplication" msgid="4533185947064773386">"Gauzatu ekintza hau erabilita:"</string>
     <string name="whichApplicationNamed" msgid="8260158865936942783">"Osatu ekintza %1$s erabiliz"</string>
     <string name="whichApplicationLabel" msgid="7425855495383818784">"Osatu ekintza"</string>
-    <string name="whichViewApplication" msgid="3272778576700572102">"Ireki honekin:"</string>
+    <string name="whichViewApplication" msgid="3272778576700572102">"Ireki honekin"</string>
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Irekin %1$s aplikazioarekin"</string>
     <string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ireki"</string>
     <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Ireki <xliff:g id="HOST">%1$s</xliff:g> ostalariko estekak honekin:"</string>
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"Ezin da konektatu Internetera <xliff:g id="NETWORK_SSID">%1$s</xliff:g> sarearen bidez"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Sakatu aukerak ikusteko"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Sare mugikorra ezin da konektatu Internetera"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Sarea ezin da konektatu Internetera"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Ezin da atzitu DNS zerbitzari pribatua"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Konektatuta"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> sareak konektagarritasun murriztua du"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Sakatu hala ere konektatzeko"</string>
@@ -1645,7 +1648,7 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Idatzi berriro PUK kode zuzena. Hainbat saiakera oker eginez gero, betiko desgaituko da SIMa."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodeak ez datoz bat"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Eredua marrazteko saiakera gehiegi egin dira"</string>
-    <string name="kg_login_instructions" msgid="1100551261265506448">"Desblokeatzeko, hasi saioa Google kontuarekin."</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Desblokeatzeko, hasi saioa Google-ko kontuarekin."</string>
     <string name="kg_login_username_hint" msgid="5718534272070920364">"Erabiltzaile-izena (helbide elektronikoa)"</string>
     <string name="kg_login_password_hint" msgid="9057289103827298549">"Pasahitza"</string>
     <string name="kg_login_submit_button" msgid="5355904582674054702">"Hasi saioa"</string>
@@ -1962,9 +1965,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Gorde"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Ez, eskerrik asko"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Eguneratu"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Egin aurrera"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"pasahitza"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"helbidea"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kreditu-txartela"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"zordunketa-txartela"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"ordainketa-txartela"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"txartela"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"erabiltzaile-izena"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"helbide elektronikoa"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Ez larritu eta bilatu babesleku bat inguruan."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 33421c0..16382638 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> به اینترنت دسترسی ندارد"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"برای گزینه‌ها ضربه بزنید"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"شبکه تلفن همراه به اینترنت دسترسی ندارد"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"شبکه به اینترنت دسترسی ندارد"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"‏سرور DNS خصوصی قابل دسترسی نیست"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"متصل"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> اتصال محدودی دارد"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"به‌هرصورت، برای اتصال ضربه بزنید"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"ذخیره"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"نه سپاسگزارم"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"به‌روزرسانی"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"ادامه"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"گذرواژه"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"نشانی"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"کارت‌ اعتباری"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"کارت نقدی"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"کارت پرداخت"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"کارت"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"نام کاربری"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"نشانی ایمیل"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"آرام باشید و پناهگاهی در این اطراف پیدا کنید."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 124a160..5b050c3 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ei ole yhteydessä internetiin"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Näytä vaihtoehdot napauttamalla."</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobiiliverkko ei ole yhteydessä internetiin"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Verkko ei ole yhteydessä internetiin"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Ei pääsyä yksityiselle DNS-palvelimelle"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Yhdistetty"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> toimii rajoitetulla yhteydellä"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Yhdistä napauttamalla"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Tallenna"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Ei kiitos"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Muuta"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Jatka"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"salasana"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"osoite"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"luottokortti"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"debit-kortti"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"maksukortti"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"kortti"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"käyttäjänimi"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"sähköpostiosoite"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Pysy rauhallisena ja hakeudu lähimpään suojapaikkaan."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index ecfdcd2..02c8043 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -299,7 +299,7 @@
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Microphone"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"enregistrer des fichiers audio"</string>
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à enregistrer l\'audio?"</string>
-    <string name="permgrouplab_activityRecognition" msgid="1565108047054378642">"données d\'activité physique"</string>
+    <string name="permgrouplab_activityRecognition" msgid="1565108047054378642">"Activité physique"</string>
     <string name="permgroupdesc_activityRecognition" msgid="6949472038320473478">"accéder à vos activités physiques"</string>
     <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"Autoriser « <xliff:g id="APP_NAME">%1$s</xliff:g> » à accéder à vos activités physiques?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Appareil photo"</string>
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"Le réseau <xliff:g id="NETWORK_SSID">%1$s</xliff:g> n\'offre aucun accès à Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Touchez pour afficher les options"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Le réseau cellulaire n\'offre aucun accès à Internet"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Le réseau n\'offre aucun accès à Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Impossible d\'accéder au serveur DNS privé"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Connecté"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Le réseau <xliff:g id="NETWORK_SSID">%1$s</xliff:g> offre une connectivité limitée"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Touchez pour vous connecter quand même"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Enregistrer"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Non, merci"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Mettre à jour"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Continuer"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"mot de passe"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"adresse"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"carte de crédit"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"carte de débit"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"carte de paiement"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"carte"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"nom d\'utilisateur"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"adresse de courriel"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Restez calme et cherchez un abri à proximité."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 1a44b79..b5b0a56 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"Aucune connexion à Internet pour <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Appuyez ici pour afficher des options."</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Le réseau mobile ne dispose d\'aucun accès à Internet"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Le réseau ne dispose d\'aucun accès à Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Impossible d\'accéder au serveur DNS privé"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Connecté"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"La connectivité de <xliff:g id="NETWORK_SSID">%1$s</xliff:g> est limitée"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Appuyer pour se connecter quand même"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Enregistrer"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Non, merci"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Mettre à jour"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Continuer"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"mot de passe"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"adresse"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"carte de paiement"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"carte de débit"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"carte de paiement"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"carte"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"nom d\'utilisateur"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"adresse e-mail"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Restez calme et cherchez un abri à proximité."</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 933fbab..bf3b3bd 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> non ten acceso a Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toca para ver opcións."</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"A rede de telefonía móbil non ten acceso a Internet"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"A rede non ten acceso a Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Non se puido acceder ao servidor DNS privado"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Estableceuse conexión"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"A conectividade de <xliff:g id="NETWORK_SSID">%1$s</xliff:g> é limitada"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Toca para conectarte de todas formas"</string>
@@ -1962,9 +1965,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Gardar"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Non, grazas"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Actualizar"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Continuar"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"contrasinal"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"enderezo"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"tarxeta de crédito"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"tarxeta de débito"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"tarxeta de pago"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"tarxeta"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"nome de usuario"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"enderezo de correo electrónico"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Mantén a calma e busca refuxio cerca."</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 05e5a4e..66bba23 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ઇન્ટરનેટ ઍક્સેસ ધરાવતું નથી"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"વિકલ્પો માટે ટૅપ કરો"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"મોબાઇલ નેટવર્ક કોઈ ઇન્ટરનેટ ઍક્સેસ ધરાવતું નથી"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"નેટવર્ક કોઈ ઇન્ટરનેટ ઍક્સેસ ધરાવતું નથી"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"ખાનગી DNS સર્વર ઍક્સેસ કરી શકાતા નથી"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"કનેક્ટેડ"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> મર્યાદિત કનેક્ટિવિટી ધરાવે છે"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"છતાં કનેક્ટ કરવા માટે ટૅપ કરો"</string>
@@ -1962,9 +1965,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"સાચવો"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"ના, આભાર"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"અપડેટ કરો"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"ચાલુ રાખો"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"પાસવર્ડ"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"સરનામું"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ક્રેડિટ કાર્ડ"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"ડેબિટ કાર્ડ"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"ચુકવણી કાર્ડ"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"કાર્ડ"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"વપરાશકર્તાનામ"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"ઇમેઇલ સરનામું"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"શાંત રહો અને નજીકમાં આશ્રય લો."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index f16ad65..717c7ae 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> का इंटरनेट नहीं चल रहा है"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"विकल्पों के लिए टैप करें"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"मोबाइल नेटवर्क पर इंटरनेट ऐक्सेस नहीं है"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"इस नेटवर्क पर इंटरनेट ऐक्सेस नहीं है"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"निजी डीएनएस सर्वर को ऐक्सेस नहीं किया जा सकता"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"जुड़ गया है"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> की कनेक्टिविटी सीमित है"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"फिर भी कनेक्ट करने के लिए टैप करें"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"सेव करें"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"नहीं, धन्यवाद"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"अपडेट करें"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"जारी रखें"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"पासवर्ड"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"पता"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"क्रेडिट कार्ड"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"डेबिट कार्ड"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"भुगतान कार्ड"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"कार्ड"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"उपयोगकर्ता का नाम"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"ईमेल पता"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"शांत रहें और आस-पास शरण लेने की जगह तलाशें."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 45c39f2..00da024 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1296,6 +1296,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nema pristup internetu"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dodirnite za opcije"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobilna mreža nema pristup internetu"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Mreža nema pristup internetu"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Nije moguće pristupiti privatnom DNS poslužitelju"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Povezano"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ima ograničenu povezivost"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Dodirnite da biste se ipak povezali"</string>
@@ -1996,9 +1999,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Spremi"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Ne, hvala"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Ažuriraj"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Nastavi"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"zaporku"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"adresu"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kreditnu karticu"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"debitna kartica"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"kartica za plaćanje"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"kartica"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"korisničko ime"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"e-adresa"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Ostanite mirni i potražite sklonište u blizini."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index aac2d76..2958ca6 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"A(z) <xliff:g id="NETWORK_SSID">%1$s</xliff:g> hálózaton nincs internet-hozzáférés"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Koppintson a beállítások megjelenítéséhez"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"A mobilhálózaton nincs internet-hozzáférés"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"A hálózaton nincs internet-hozzáférés"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"A privát DNS-kiszolgálóhoz nem lehet hozzáférni"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Csatlakozva"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"A(z) <xliff:g id="NETWORK_SSID">%1$s</xliff:g> hálózat korlátozott kapcsolatot biztosít"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Koppintson, ha mindenképpen csatlakozni szeretne"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Mentés"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Nem, köszönöm"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Frissítés"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Tovább"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"jelszó"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"cím"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"hitelkártya"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"bankkártya"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"fizetőkártya"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"kártya"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"felhasználónév"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"e-mail-cím"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Őrizze meg nyugalmát, és keressen menedéket a közelben."</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index a5b4e30..967ddd0 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ցանցը չունի մուտք ինտերնետին"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Հպեք՝ ընտրանքները տեսնելու համար"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Բջջային ցանցը չի ապահովում ինտերնետ կապ"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Ցանցը միացված չէ ինտերնետին"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Մասնավոր DNS սերվերն անհասանելի է"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Միացված է"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ցանցի կապը սահմանափակ է"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Հպեք՝ միանալու համար"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Պահել"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Ոչ"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Թարմացնել"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Շարունակել"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"գաղտնաբառ"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"հասցե"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"վարկային քարտ"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"դեբետային քարտ"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"վճարային քարտ"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"քարտ"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"օգտանուն"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"էլ․ հասցե"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Պահպանեք հանգստությունը և մոտակայքում ապաստարան փնտրեք:"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 228da88..662a654 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tidak memiliki akses internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Ketuk untuk melihat opsi"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Jaringan seluler tidak memiliki akses internet"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Jaringan tidak memiliki akses internet"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Server DNS pribadi tidak dapat diakses"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Tersambung"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> memiliki konektivitas terbatas"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Ketuk untuk tetap menyambungkan"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Simpan"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Lain kali"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Update"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Lanjutkan"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"sandi"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"alamat"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kartu kredit"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"kartu debit"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"kartu pembayaran"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"kartu"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"nama pengguna"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"alamat email"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Tetap tenang dan cari tempat berlindung terdekat."</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index d0f8028..9ae165d 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> er ekki með internetaðgang"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Ýttu til að sjá valkosti"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Farsímakerfið er ekki tengt við internetið"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Netkerfið er ekki tengt við internetið"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Ekki næst í DNS-einkaþjón"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Tengt"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Tengigeta <xliff:g id="NETWORK_SSID">%1$s</xliff:g> er takmörkuð"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Ýttu til að tengjast samt"</string>
@@ -1962,9 +1965,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Vista"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Nei, takk"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Uppfæra"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Áfram"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"aðgangsorð"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"heimilisfang"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kreditkort"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"debetkort"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"greiðslukort"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"kort"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"notandanafn"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"netfang"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Sýndu stillingu og leitaðu skjóls."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 747d918..77eafcc 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -283,7 +283,7 @@
     <string name="permgrouprequest_contacts" msgid="6032805601881764300">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere ai tuoi contatti?"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Geolocalizz."</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"accedere alla posizione di questo dispositivo"</string>
-    <string name="permgrouprequest_location" msgid="3788275734953323491">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere alla posizione del dispositivo?"</string>
+    <string name="permgrouprequest_location" msgid="3788275734953323491">"Consentire a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere alla posizione del dispositivo?"</string>
     <string name="permgrouprequestdetail_location" msgid="1347189607421252902">"L\'app avrà accesso alla posizione soltanto quando la usi"</string>
     <string name="permgroupbackgroundrequest_location" msgid="5039063878675613235">"Consentire a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere &lt;b&gt;sempre&lt;/b&gt; alla posizione di questo dispositivo?"</string>
     <string name="permgroupbackgroundrequestdetail_location" msgid="4597006851453417387">"L\'app al momento può accedere alla posizione soltanto mentre la usi"</string>
@@ -301,7 +301,7 @@
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di registrare audio?"</string>
     <string name="permgrouplab_activityRecognition" msgid="1565108047054378642">"Attività fisica"</string>
     <string name="permgroupdesc_activityRecognition" msgid="6949472038320473478">"Consente di accedere all\'attività fisica"</string>
-    <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"Vuoi consentire a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere alla tua attività fisica?"</string>
+    <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"Consentire a &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di accedere alla tua attività fisica?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Fotocamera"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"scattare foto e registrare video"</string>
     <string name="permgrouprequest_camera" msgid="1299833592069671756">"Consentire all\'app &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; di scattare foto e registrare video?"</string>
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> non ha accesso a Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tocca per le opzioni"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"La rete mobile non ha accesso a Internet"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"La rete non ha accesso a Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Non è possibile accedere al server DNS privato"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Connesso"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ha una connettività limitata"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Tocca per connettere comunque"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Salva"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"No, grazie"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Aggiorna"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Continua"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"password"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"indirizzo"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"carta di credito"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"carta di debito"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"carta di pagamento"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"carta"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"nome utente"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"indirizzo email"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Mantieni la calma e cerca riparo nelle vicinanze."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 4c12e43..2888a53 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -304,13 +304,13 @@
     <string name="permgrouprequest_storage" msgid="7885942926944299560">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה לתמונות, למדיה ולקבצים במכשיר?"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"מיקרופון"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"הקלטת אודיו"</string>
-    <string name="permgrouprequest_microphone" msgid="9167492350681916038">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאה להקליט אודיו?"</string>
+    <string name="permgrouprequest_microphone" msgid="9167492350681916038">"‏לאשר לאפליקציית &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; להקליט אודיו?"</string>
     <string name="permgrouplab_activityRecognition" msgid="1565108047054378642">"פעילות גופנית"</string>
     <string name="permgroupdesc_activityRecognition" msgid="6949472038320473478">"גישה לפעילות הגופנית שלך"</string>
     <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"‏האם לאפשר לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; גישה לפעילות הגופנית שלך?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"מצלמה"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"צילום תמונות והקלטת וידאו"</string>
-    <string name="permgrouprequest_camera" msgid="1299833592069671756">"‏לאשר לאפליקציה של &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; לצלם תמונות וסרטונים?"</string>
+    <string name="permgrouprequest_camera" msgid="1299833592069671756">"‏לאשר לאפליקציית &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; לצלם תמונות וסרטונים?"</string>
     <string name="permgrouplab_calllog" msgid="8798646184930388160">"יומני שיחות"</string>
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"קריאה וכתיבה של יומן השיחות של הטלפון"</string>
     <string name="permgrouprequest_calllog" msgid="8487355309583773267">"‏לתת לאפליקציה &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; הרשאת גישה ליומני השיחות של הטלפון?"</string>
@@ -1318,6 +1318,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"ל-<xliff:g id="NETWORK_SSID">%1$s</xliff:g> אין גישה לאינטרנט"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"הקש לקבלת אפשרויות"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"לרשת הסלולרית אין גישה לאינטרנט"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"לרשת אין גישה לאינטרנט"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"‏לא ניתן לגשת לשרת DNS הפרטי"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"הרשת מחוברת"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"הקישוריות של <xliff:g id="NETWORK_SSID">%1$s</xliff:g> מוגבלת"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"כדי להתחבר למרות זאת יש להקיש"</string>
@@ -2031,9 +2034,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"שמירה"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"לא, תודה"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"עדכון"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"המשך"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"סיסמה"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"כתובת"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"כרטיס אשראי"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"כרטיס חיוב"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"כרטיס תשלום"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"כרטיס"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"שם משתמש"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"כתובת אימייל"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"הישאר רגוע וחפש מחסה בקרבת מקום."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 98600b8..2a2b71b 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -301,7 +301,7 @@
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"音声の録音を「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
     <string name="permgrouplab_activityRecognition" msgid="1565108047054378642">"身体活動"</string>
     <string name="permgroupdesc_activityRecognition" msgid="6949472038320473478">"身体活動にアクセス"</string>
-    <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"身体活動へのアクセスを「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
+    <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"身体活動データへのアクセスを「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"カメラ"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"写真と動画の撮影"</string>
     <string name="permgrouprequest_camera" msgid="1299833592069671756">"写真と動画の撮影を「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> はインターネットにアクセスできません"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"タップしてその他のオプションを表示"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"モバイル ネットワークがインターネットに接続されていません"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"ネットワークがインターネットに接続されていません"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"プライベート DNS サーバーにアクセスできません"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"接続しました"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> の接続が制限されています"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"接続するにはタップしてください"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"はい"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"いいえ"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"更新"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"続行"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"パスワード"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"住所"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"クレジット カード"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"デビットカード"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"支払いカード"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"カード"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"ユーザー名"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"メールアドレス"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"強い揺れに備えてください"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index cc8ecc2..ebc7f2a 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-ს არ აქვს ინტერნეტზე წვდომა"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"შეეხეთ ვარიანტების სანახავად"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"მობილურ ქსელს არ აქვს ინტერნეტზე წვდომა"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"ქსელს არ აქვს ინტერნეტზე წვდომა"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"პირად DNS სერვერზე წვდომა შეუძლებელია"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"დაკავშირებულია"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-ის კავშირები შეზღუდულია"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"შეეხეთ, თუ მაინც გსურთ დაკავშირება"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"შენახვა"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"არა, გმადლობთ"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"განახლება"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"გაგრძელება"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"პაროლი"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"მისამართი"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"საკრედიტო ბარათი"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"სადებეტო ბარათი"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"გადახდის ბარათი"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"ბარათი"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"მომხმარებლის სახელი"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"ელფოსტის მისამართი"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"შეინარჩუნეთ სიმშვიდე და იპოვეთ ახლომდებარე თავშესაფარი."</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index db9fad2..281db7a 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> желісінің интернетті пайдалану мүмкіндігі шектеулі."</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Опциялар үшін түртіңіз"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Мобильдік желі интернетке қосылмаған."</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Желі интернетке қосылмаған."</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Жеке DNS серверіне кіру мүмкін емес."</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Жалғанды"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> желісінің қосылу мүмкіндігі шектеулі."</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Бәрібір жалғау үшін түртіңіз."</string>
@@ -1962,9 +1965,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Сақтау"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Жоқ, рақмет"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Жаңарту"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Жалғастыру"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"құпия сөз"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"мекенжай"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"несие картасы"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"дебеттік карта"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"төлем картасы"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"карта"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"пайдаланушы аты"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"электрондық пошта мекенжайы"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Сабыр сақтап, жақын жерден баспана іздеңіз."</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 021da3e..532e3c7 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1276,6 +1276,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> មិនមាន​ការតភ្ជាប់អ៊ីនធឺណិត​ទេ"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ប៉ះសម្រាប់ជម្រើស"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"បណ្ដាញ​ទូរសព្ទ​ចល័ត​មិនមានការតភ្ជាប់​អ៊ីនធឺណិតទេ"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"បណ្ដាញ​មិនមាន​ការតភ្ជាប់​អ៊ីនធឺណិតទេ"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"មិនអាច​ចូលប្រើ​ម៉ាស៊ីនមេ DNS ឯកជន​បានទេ"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"បានភ្ជាប់"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> មានការតភ្ជាប់​មានកម្រិត"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"មិន​អី​ទេ ចុច​​ភ្ជាប់​ចុះ"</string>
@@ -1963,9 +1966,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"រក្សាទុក"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"ទេ អរគុណ"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"ធ្វើ​បច្ចុប្បន្នភាព"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"បន្ត"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"ពាក្យ​សម្ងាត់"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"អាសយដ្ឋាន"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"បណ្ណ​ឥណទាន"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"បណ្ណ​ឥណពន្ធ"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"កាតទូទាត់ប្រាក់"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"កាត"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"ឈ្មោះ​អ្នក​ប្រើប្រាស់"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"អាសយដ្ឋាន​អ៊ីមែល"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"សូមរក្សាភាពស្ងប់ស្ងាត់ ហើយស្វែងរកជម្រកសុវត្ថិភាពដែលនៅជិត។"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index edcb6d1..3fb6766 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -305,13 +305,13 @@
     <string name="permgrouplab_camera" msgid="4820372495894586615">"ಕ್ಯಾಮರಾ"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"ಚಿತ್ರಗಳನ್ನು ತೆಗೆಯಲು, ವೀಡಿಯೊ ರೆಕಾರ್ಡ್ ಮಾಡಲು"</string>
     <string name="permgrouprequest_camera" msgid="1299833592069671756">"ಚಿತ್ರಗಳನ್ನು ಸೆರೆಹಿಡಿಯಲು ಮತ್ತು ವೀಡಿಯೊ ರೆಕಾರ್ಡ್‌ ಮಾಡಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
-    <string name="permgrouplab_calllog" msgid="8798646184930388160">"ಕರೆಯ ಲಾಗ್‌ಗಳು"</string>
+    <string name="permgrouplab_calllog" msgid="8798646184930388160">"ಕರೆಯ ಲಾಗ್‌"</string>
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"ಪೋನ್‌ ಕರೆಯ ಲಾಗ್‌ ಅನ್ನು ಓದಿ ಮತ್ತು ಬರೆಯಿರಿ"</string>
     <string name="permgrouprequest_calllog" msgid="8487355309583773267">"ನಿಮ್ಮ ಫೋನ್‌ ಕರೆಯ ಲಾಗ್‌ಗಳಿಗೆ ಪ್ರವೇಶ ಪಡೆಯಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"ಫೋನ್"</string>
     <string name="permgroupdesc_phone" msgid="6234224354060641055">"ಫೋನ್ ಕರೆ ಮಾಡಲು ಹಾಗೂ ನಿರ್ವಹಿಸಲು"</string>
     <string name="permgrouprequest_phone" msgid="9166979577750581037">"ಫೋನ್ ಕರೆಗಳನ್ನು ಮಾಡಲು ಮತ್ತು ನಿರ್ವಹಿಸಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
-    <string name="permgrouplab_sensors" msgid="4838614103153567532">"ದೇಹದ ಸೆನ್ಸರ್‌ಗಳು"</string>
+    <string name="permgrouplab_sensors" msgid="4838614103153567532">"ದೇಹದ ಸೆನ್ಸರ್‌"</string>
     <string name="permgroupdesc_sensors" msgid="7147968539346634043">"ನಿಮ್ಮ ಮುಖ್ಯ ಲಕ್ಷಣಗಳ ಕುರಿತು ಸೆನ್ಸಾರ್ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
     <string name="permgrouprequest_sensors" msgid="6349806962814556786">"ನಿಮ್ಮ ಮುಖ್ಯ ಲಕ್ಷಣಗಳ ಕುರಿತು ಸೆನ್ಸರ್ ಡೇಟಾವನ್ನು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"ವಿಂಡೋ ವಿಷಯವನ್ನು ಹಿಂಪಡೆಯುತ್ತದೆ"</string>
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ಆಯ್ಕೆಗಳಿಗೆ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"ಮೊಬೈಲ್ ನೆಟ್‌ವರ್ಕ್‌ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"ನೆಟ್‌ವರ್ಕ್‌ ಇಂಟರ್ನೆಟ್‌ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"ಖಾಸಗಿ DNS ಸರ್ವರ್ ಅನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ಸೀಮಿತ ಸಂಪರ್ಕ ಕಲ್ಪಿಸುವಿಕೆಯನ್ನು ಹೊಂದಿದೆ"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"ಹೇಗಾದರೂ ಸಂಪರ್ಕಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
@@ -1962,9 +1965,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"ಉಳಿಸಿ"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"ಬೇಡ"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"ಅಪ್‌ಡೇಟ್"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"ಮುಂದುವರಿಯಿರಿ"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"ಪಾಸ್‌ವರ್ಡ್"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"ವಿಳಾಸ"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ಕ್ರೆಡಿಟ್ ಕಾರ್ಡ್"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"ಡೆಬಿಟ್ ಕಾರ್ಡ್"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"ಪಾವತಿ ಕಾರ್ಡ್"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"ಕಾರ್ಡ್"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"ಬಳಕೆದಾರರ ಹೆಸರು"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"ಇಮೇಲ್ ವಿಳಾಸ"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"ಶಾಂತರಾಗಿರಿ ಮತ್ತು ಸಮೀಪದಲ್ಲೆಲ್ಲಾದರೂ ಆಶ್ರಯ ಪಡೆದುಕೊಳ್ಳಿ."</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 2f06bee..acc6e95 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>이(가) 인터넷에 액세스할 수 없습니다."</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"탭하여 옵션 보기"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"모바일 네트워크에 인터넷이 연결되어 있지 않습니다."</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"네트워크에 인터넷이 연결되어 있지 않습니다."</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"비공개 DNS 서버에 액세스할 수 없습니다."</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"연결되었습니다."</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>에서 연결을 제한했습니다."</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"계속 연결하려면 탭하세요."</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"저장"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"사용 안함"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"업데이트"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"계속"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"비밀번호"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"주소"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"신용카드"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"체크카드"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"결제 카드"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"카드"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"사용자 이름"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"이메일 주소"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"침착하게 가까운 대피소를 찾으세요."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 2353ed0..db54c42 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -305,7 +305,7 @@
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Камера"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"сүрөт жана видео тартууга"</string>
     <string name="permgrouprequest_camera" msgid="1299833592069671756">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна сүрөттөр менен видеолорду тартканга уруксат бересизби?"</string>
-    <string name="permgrouplab_calllog" msgid="8798646184930388160">"Чалуулар тизмелери"</string>
+    <string name="permgrouplab_calllog" msgid="8798646184930388160">"Чалуулар тизмеси"</string>
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"телефондогу чалуулар тизмесин окуу жана жазуу"</string>
     <string name="permgrouprequest_calllog" msgid="8487355309583773267">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; колдонмосуна телефондогу чалуулар тизмесин пайдаланууга уруксат берилсинби?"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"Телефон"</string>
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> Интернетке туташуусу жок"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Параметрлерди ачуу үчүн таптап коюңуз"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Мобилдик Интернет жок"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Тармактын Интернет байланышы жок"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Жеке DNS сервери жеткиликсиз"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Туташты"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> байланышы чектелген"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Баары бир туташуу үчүн таптаңыз"</string>
@@ -1668,7 +1671,7 @@
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Алып салуу"</string>
     <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Сунушталган деңгээлден да катуулатып уккуңуз келеби?\n\nМузыканы узакка чейин катуу уксаңыз, угууңуз начарлап кетиши мүмкүн."</string>
-    <string name="accessibility_shortcut_warning_dialog_title" msgid="8404780875025725199">"Атайын мүмкүнчүлүктөр функциясынын кыска жолу колдонулсунбу?"</string>
+    <string name="accessibility_shortcut_warning_dialog_title" msgid="8404780875025725199">"Ыкчам иштетесизби?"</string>
     <string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Атайын мүмкүнчүлүктөр функциясын пайдалануу үчүн, ал күйгүзүлгөндө, үндү катуулатып/акырындаткан эки баскычты тең үч секунддай кое бербей басып туруңуз.\n\n Учурдагы атайын мүмкүнчүлүктөрдүн жөндөөлөрү:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\nЖөндөөлөр &gt; Атайын мүмкүнчүлүктөр бөлүмүнөн өзгөртө аласыз."</string>
     <string name="disable_accessibility_shortcut" msgid="627625354248453445">"Кыска жолду өчүрүү"</string>
     <string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Кыска жолду колдонуу"</string>
@@ -1963,9 +1966,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Сактоо"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Жок, рахмат"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Жаңыртуу"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Улантуу"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"сырсөз"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"дарек"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"насыя картасы"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"дебет картасы"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"төлөм картасы"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"карта"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"колдонуучунун аты"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"электрондук почта дареги"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Эс алып, жакын жерден калканч издеңиз."</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index a83fae1..6ef4cca 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ແຕະເພື່ອເບິ່ງຕົວເລືອກ"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"ເຄືອຂ່າຍມືຖືບໍ່ສາມາດເຂົ້າເຖິງອິນເຕີເນັດໄດ້"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"ເຄືອຂ່າຍບໍ່ສາມາດເຂົ້າເຖິງອິນເຕີເນັດໄດ້"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"ບໍ່ສາມາດເຂົ້າເຖິງເຊີບເວີ DNS ສ່ວນຕົວໄດ້"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"ເຊື່ອມຕໍ່ແລ້ວ"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ມີການເຊື່ອມຕໍ່ທີ່ຈຳກັດ"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"ແຕະເພື່ອຢືນຢັນການເຊື່ອມຕໍ່"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"ບັນທຶກ"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"ບໍ່, ຂອບໃຈ"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"ອັບເດດ"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"ສືບຕໍ່"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"​ລະ​ຫັດ​ຜ່ານ"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"ທີ່ຢູ່"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ບັດເຄຣດິດ"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"ບັດເດບິດ"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"ບັດຈ່າຍເງິນ"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"ບັດ"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"ຊື່ຜູ້ໃຊ້"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"ທີ່ຢູ່ອີເມລ"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"ໃຈເຢັນໆ ແລະ ຊອກຫາບ່ອນພັກຢູ່ໃກ້ໆ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index fdd5d2a..f2c17c3 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1318,6 +1318,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"„<xliff:g id="NETWORK_SSID">%1$s</xliff:g>“ negali pasiekti interneto"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Palieskite, kad būtų rodomos parinktys."</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobiliojo ryšio tinkle nėra prieigos prie interneto"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Tinkle nėra prieigos prie interneto"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Privataus DNS serverio negalima pasiekti"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Prisijungta"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"„<xliff:g id="NETWORK_SSID">%1$s</xliff:g>“ ryšys apribotas"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Palieskite, jei vis tiek norite prisijungti"</string>
@@ -2031,9 +2034,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Išsaugoti"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Ne, ačiū"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Atnaujinti"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Tęsti"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"slaptažodį"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"adresą"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kredito kortelę"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"debeto kortelė"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"mokėjimo kortelė"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"kortelė"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"naudotojo vardas"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"el. pašto adresas"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Nesijaudinkite ir ieškokite prieglobsčio netoliese."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index d1b7764..be8d5d1 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1296,6 +1296,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"Tīklā <xliff:g id="NETWORK_SSID">%1$s</xliff:g> nav piekļuves internetam"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Pieskarieties, lai skatītu iespējas."</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobilajā tīklā nav piekļuves internetam."</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Tīklā nav piekļuves internetam."</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Nevar piekļūt privātam DNS serverim."</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Izveidots savienojums"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Tīklā <xliff:g id="NETWORK_SSID">%1$s</xliff:g> ir ierobežota savienojamība"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Lai tik un tā izveidotu savienojumu, pieskarieties"</string>
@@ -1996,9 +1999,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Saglabāt"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Nē, paldies"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Atjaunināt"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Turpināt"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"paroli"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"adresi"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kredītkartes informāciju"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"debetkarte"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"maksājumu karte"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"karte"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"lietotājvārds"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"e-pasta adrese"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Saglabājiet mieru un meklējiet tuvumā patvērumu."</string>
diff --git a/core/res/res/values-mcc208-mnc10-fr/strings.xml b/core/res/res/values-mcc208-mnc10-fr/strings.xml
new file mode 100644
index 0000000..a1a2c8f
--- /dev/null
+++ b/core/res/res/values-mcc208-mnc10-fr/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">Utiliser les appels Wi-Fi lorsque le service est disponible</string>
+</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index d30c8f2..ea9a6b4 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> нема интернет-пристап"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Допрете за опции"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Мобилната мрежа нема интернет-пристап"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Мрежата нема интернет-пристап"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Не може да се пристапи до приватниот DNS-сервер"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Поврзано"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> има ограничена поврзливост"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Допрете за да се поврзете и покрај тоа"</string>
@@ -1964,9 +1967,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Зачувај"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Не, фала"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Ажурирај"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Продолжи"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"лозинка"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"адреса"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"кредитна картичка"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"дебитна картичка"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"платежна картичка"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"картичка"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"корисничко име"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"адреса на е-пошта"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Бидете смирени и побарајте засолниште во близина."</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 5a604fb..5250df5 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -278,7 +278,7 @@
     <string name="android_system_label" msgid="6577375335728551336">"Android സിസ്റ്റം"</string>
     <string name="user_owner_label" msgid="8836124313744349203">"വ്യക്തിഗത പ്രൊഫൈലിലേക്ക് മാറുക"</string>
     <string name="managed_profile_label" msgid="8947929265267690522">"ഔദ്യോഗിക പ്രൊഫൈലിലേക്ക് മാറുക"</string>
-    <string name="permgrouplab_contacts" msgid="3657758145679177612">"കോൺടാക്റ്റുകൾ"</string>
+    <string name="permgrouplab_contacts" msgid="3657758145679177612">"കോൺടാക്റ്റ്"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"നിങ്ങളുടെ കോൺടാക്റ്റുകൾ ആക്‌സസ്സ് ചെയ്യുക"</string>
     <string name="permgrouprequest_contacts" msgid="6032805601881764300">"നിങ്ങളുടെ കോണ്‍ടാക്റ്റുകള്‍ ആക്‌സസ് ചെയ്യാൻ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ആപ്പിനെ അനുവദിക്കണോ?"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"ലൊക്കേഷൻ"</string>
@@ -299,19 +299,19 @@
     <string name="permgrouplab_microphone" msgid="171539900250043464">"മൈക്രോഫോണ്‍"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ഓഡിയോ റെക്കോർഡ് ചെയ്യുക"</string>
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"ഓഡിയോ റെക്കോർഡ് ചെയ്യാൻ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ആപ്പിനെ അനുവദിക്കണോ?"</string>
-    <string name="permgrouplab_activityRecognition" msgid="1565108047054378642">"ശാരീരിക പ്രവർത്തനം"</string>
+    <string name="permgrouplab_activityRecognition" msgid="1565108047054378642">"കായിക പ്രവർത്തനം"</string>
     <string name="permgroupdesc_activityRecognition" msgid="6949472038320473478">"ശാരീരിക പ്രവർത്തനം ആക്‌സസ് ചെയ്യുക"</string>
     <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-നെ നിങ്ങളുടെ ശാരീരിക പ്രവർത്തനം ആക്‌സസ് ചെയ്യാൻ അനുവദിക്കണോ?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"ക്യാമറ"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"ചിത്രങ്ങളെടുത്ത് വീഡിയോ റെക്കോർഡുചെയ്യുക"</string>
     <string name="permgrouprequest_camera" msgid="1299833592069671756">"ചിത്രം എടുക്കാനും വീഡിയോ റെക്കോർഡ് ചെയ്യാനും &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ആപ്പിനെ അനുവദിക്കണോ?"</string>
-    <string name="permgrouplab_calllog" msgid="8798646184930388160">"കോൾ ലോഗുകൾ"</string>
+    <string name="permgrouplab_calllog" msgid="8798646184930388160">"കോൾ ലോഗ്"</string>
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"ഫോൺ കോൾ ലോഗ് വായിക്കുകയും എഴുതുകയും ചെയ്യുക"</string>
     <string name="permgrouprequest_calllog" msgid="8487355309583773267">"നിങ്ങളുടെ ഫോൺ കോൾ ലോഗുകൾ ആക്സസ് ചെയ്യാൻ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ആപ്പിനെ അനുവദിക്കണോ?"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"ഫോണ്‍"</string>
     <string name="permgroupdesc_phone" msgid="6234224354060641055">"ഫോൺ വിളിക്കുകയും നിയന്ത്രിക്കുകയും ചെയ്യുക"</string>
     <string name="permgrouprequest_phone" msgid="9166979577750581037">"ഫോൺ കോളുകൾ ചെയ്യാനും അവ മാനേജ് ചെയ്യാനും &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ആപ്പിനെ അനുവദിക്കണോ?"</string>
-    <string name="permgrouplab_sensors" msgid="4838614103153567532">"ബോഡി സെൻസറുകൾ"</string>
+    <string name="permgrouplab_sensors" msgid="4838614103153567532">"ബോഡി സെൻസർ"</string>
     <string name="permgroupdesc_sensors" msgid="7147968539346634043">"നിങ്ങളുടെ ജീവാധാര ലക്ഷണങ്ങളെ കുറിച്ചുള്ള സെൻസർ വിവരങ്ങൾ ആക്സസ് ചെയ്യുക"</string>
     <string name="permgrouprequest_sensors" msgid="6349806962814556786">"നിങ്ങളുടെ ജീവധാരണ ലക്ഷണങ്ങളെ കുറിച്ചുള്ള സെൻസർ ഡാറ്റ ആക്‌സസ് ചെയ്യാൻ &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ആപ്പിനെ അനുവദിക്കണോ?"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"വിൻഡോ ഉള്ളടക്കം വീണ്ടെടുക്കുക"</string>
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> എന്നതിന് ഇന്റർനെറ്റ് ആക്‌സസ് ഇല്ല"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ഓപ്ഷനുകൾക്ക് ടാപ്പുചെയ്യുക"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"മൊബെെൽ നെറ്റ്‌വർക്കിന് ഇന്റർനെറ്റ് ആക്‌സസ് ഇല്ല"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"നെറ്റ്‌വർക്കിന് ഇന്റർനെറ്റ് ആക്‌സസ് ഇല്ല"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"സ്വകാര്യ DNS സെർവർ ആക്‌സസ് ചെയ്യാനാവില്ല"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"കണക്‌റ്റ് ചെയ്‌തു"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> എന്നതിന് പരിമിതമായ കണക്റ്റിവിറ്റി ഉണ്ട്"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"ഏതുവിധേനയും കണക്‌റ്റ് ചെയ്യാൻ ടാപ്പ് ചെയ്യുക"</string>
@@ -1962,9 +1965,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"സംരക്ഷിക്കുക"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"വേണ്ട, നന്ദി"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"അപ്ഡേറ്റ് ചെയ്യുക"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"തുടരുക"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"പാസ്‌വേഡ്"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"വിലാസം"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ക്രെഡിറ്റ് കാർഡ്"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"ഡെബിറ്റ് കാർഡ്"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"പെയ്‌മെന്റ് കാർഡ്"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"കാർഡ്"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"ഉപയോക്തൃനാമം"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"വിലാസം നൽകുക"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"പരിഭ്രമിക്കാതിരിക്കുക, അടുത്തുള്ള അഭയകേന്ദ്രം തേടുക."</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index f4c6b60..9a4ffae 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-д интернэтийн хандалт алга"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Сонголт хийхийн тулд товшино уу"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Мобайл сүлжээнд интернэт хандалт байхгүй байна"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Сүлжээнд интернэт хандалт байхгүй байна"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Хувийн DNS серверт хандах боломжгүй байна"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Холбогдсон"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> зарим үйлчилгээнд хандах боломжгүй байна"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Ямар ч тохиолдолд холбогдохын тулд товших"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Хадгалах"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Үгүй, баярлалаа"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Шинэчлэх"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Үргэлжлүүлэх"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"нууц үг"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"хаяг"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"кредит карт"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"дебит карт"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"төлбөрийн карт"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"карт"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"хэрэглэгчийн нэр"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"имэйл хаяг"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Тайван байж, ойролцоох нуугдах газар хайна уу."</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 4fb2347..39f614a 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -345,7 +345,7 @@
     <string name="permlab_receiveMms" msgid="1821317344668257098">"मजकूर मेसेज मिळवा (MMS)"</string>
     <string name="permdesc_receiveMms" msgid="533019437263212260">"MMS मेसेज प्राप्त करण्यास आणि त्यावर प्रक्रिया करण्यास अ‍ॅप ला अनुमती देते. म्हणजेच अ‍ॅप आपल्या डिव्हाइसवर पाठविलेले मेसेज तुम्हाला न दर्शवता त्यांचे परीक्षण करू किंवा ते हटवू शकतो."</string>
     <string name="permlab_bindCellBroadcastService" msgid="4468585041824555604">"सेल प्रसारण मेसेज फॉरवर्ड करा"</string>
-    <string name="permdesc_bindCellBroadcastService" msgid="9073440260695196089">"सेल प्रसारण मेसेज मिळाल्यानंतर ते फॉरवर्ड करण्यासाठी अॅपला सेल प्रसारण मॉड्यूलमध्ये प्रतिबद्ध करण्याची अनुमती देते. काही स्थानांमध्ये तुम्हाला आणीबाणीच्या परिस्थीतींची चेतावणी देण्यासाठी सेल प्रसारण सूचना वितरित केल्या जातात. दुर्भावनापूर्ण अॅप्स आणीबाणी सेल प्रसारण मिळवतात तेव्हा ती तुमच्या डिव्हाइसच्या परफॉर्मन्समध्ये किंवा कामामध्ये कदाचित व्यत्यय आणू शकतात."</string>
+    <string name="permdesc_bindCellBroadcastService" msgid="9073440260695196089">"सेल प्रसारण मेसेज मिळाल्यानंतर ते फॉरवर्ड करण्यासाठी अॅपला सेल प्रसारण मॉड्यूलमध्ये प्रतिबद्ध करण्याची अनुमती देते. काही स्थानांमध्ये तुम्हाला आणीबाणीच्या परिस्थीतींची चेतावणी देण्यासाठी सेल प्रसारण सूचना वितरित केल्या जातात. दुर्भावनापूर्ण अ‍ॅप्स आणीबाणी सेल प्रसारण मिळवतात तेव्हा ती तुमच्या डिव्हाइसच्या परफॉर्मन्समध्ये किंवा कामामध्ये कदाचित व्यत्यय आणू शकतात."</string>
     <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"सेल प्रसारण मेसेज वाचा"</string>
     <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"आपल्या डिव्हाइसद्वारे प्राप्त केलेले सेल प्रसारण मेसेज वाचण्यासाठी अ‍ॅप ला अनुमती देते. काही स्थानांमध्ये तुम्हाला आणीबाणीच्या परिस्थितीची चेतावणी देण्यासाठी सेल प्रसारण सूचना वितरीत केल्या जातात. आणीबाणी सेल प्रसारण प्राप्त होते तेव्हा आपल्या डिव्हाइसच्या कार्यप्रदर्शनात किंवा कार्यात दुर्भावनापूर्ण अ‍ॅप्स व्यत्यय आणू शकतात."</string>
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"सदस्यता घेतलेली फीड वाचा"</string>
@@ -394,7 +394,7 @@
     <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"रोचक प्रसारणे पाठविण्यासाठी अ‍ॅप ला अनुमती देते, जे प्रसारण समाप्त झाल्यानंतर देखील तसेच राहते. अत्याधिक वापरामुळे बरीच मेमरी वापरली जाऊन तो फोनला धीमा किंवा अस्थिर करू शकतो."</string>
     <string name="permlab_readContacts" msgid="8348481131899886131">"तुमचे संपर्क वाचा"</string>
     <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"तुम्ही कॉल केलेल्या, ईमेल केलेल्या किंवा विशिष्ट लोकांशी अन्य मार्गांनी संवाद प्रस्थापित केलेल्या लोकांच्या फ्रिक्वेन्सीसह, आपल्या टॅब्लेटवर स्टोअर केलेल्या आपल्या संपर्कांविषयीचा डेटा वाचण्यासाठी अ‍ॅप ला अनुमती देते. ही परवानगी तुमचा संपर्क डेटा सेव्ह करण्याची अ‍ॅप्स ला अनुमती देते आणि दुर्भावनापूर्ण अ‍ॅप्स आपल्या माहितीशिवाय संपर्क डेटा शेअर करू शकतात."</string>
-    <string name="permdesc_readContacts" product="tv" msgid="3890061004911027912">"तुम्ही केलेले कॉल, केलेले ईमेल किंवा विशिष्‍ट संपर्कांसह अन्य मार्गांनी केलेले कम्युनिकेशन यांची वारंवारता, यासह तुमच्या Android TV डिव्‍हाइसवर स्टोअर केलेल्‍या तुमच्या संपर्कांविषयीचा डेटा वाचण्याची अॅपला अनुमती देते. ही परवानगी अॅप्सना तुमचा संपर्क डेटा सेव्ह करण्याची अनुमती देते आणि ही दुर्भावनापूर्ण अॅप्स तुम्हाला न कळवता संपर्क डेटा शेअर करू शकतात."</string>
+    <string name="permdesc_readContacts" product="tv" msgid="3890061004911027912">"तुम्ही केलेले कॉल, केलेले ईमेल किंवा विशिष्‍ट संपर्कांसह अन्य मार्गांनी केलेले कम्युनिकेशन यांची वारंवारता, यासह तुमच्या Android TV डिव्‍हाइसवर स्टोअर केलेल्‍या तुमच्या संपर्कांविषयीचा डेटा वाचण्याची अॅपला अनुमती देते. ही परवानगी अ‍ॅप्सना तुमचा संपर्क डेटा सेव्ह करण्याची अनुमती देते आणि ही दुर्भावनापूर्ण अ‍ॅप्स तुम्हाला न कळवता संपर्क डेटा शेअर करू शकतात."</string>
     <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"तुम्ही कॉल केलेल्या, ईमेल केलेल्या किंवा विशिष्ट लोकांशी अन्य मार्गांनी संवाद प्रस्थापित केलेल्या लोकांच्या फ्रिक्वेन्सीसह, आपल्या फोनवर स्टोअर केलेल्या आपल्या संपर्कांविषयीचा डेटा वाचण्यासाठी अ‍ॅप ला अनुमती देते. ही परवानगी तुमचा संपर्क डेटा सेव्ह करण्याची अ‍ॅप्स ला अनुमती देते आणि दुर्भावनापूर्ण अ‍ॅप्स आपल्या माहितीशिवाय संपर्क डेटा शेअर करू शकतात."</string>
     <string name="permlab_writeContacts" msgid="5107492086416793544">"तुमचे संपर्क सुधारित करा"</string>
     <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"तुम्ही विशिष्ट संपर्कांशी अन्य मार्गांनी कॉल केलेल्या, ईमेल केलेल्या किंवा संवाद प्रस्थापित केलेल्या फ्रिक्वेन्सीसह, आपल्या टॅब्लेटवर स्टोअर केलेल्या आपल्या संपर्कांविषयीचा डेटा सुधारित करण्यासाठी अ‍ॅप ला अनुमती देते. ही परवानगी संपर्क डेटा हटविण्यासाठी अ‍ॅप ला अनुमती देते."</string>
@@ -404,7 +404,7 @@
     <string name="permdesc_readCallLog" msgid="3204122446463552146">"हा अ‍ॅप तुमचा कॉल इतिहास वाचू शकता."</string>
     <string name="permlab_writeCallLog" msgid="8552045664743499354">"कॉल लॉग लिहा"</string>
     <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"येणार्‍या आणि केल्या जाणार्‍या कॉलविषयीच्या डेटासह, आपल्या टॅब्लेटचा कॉल लॉग सुधारित करण्यासाठी अ‍ॅप ला अनुमती देते. दुर्भावनापूर्ण अ‍ॅप्स तुमचा कॉल लॉग मिटवण्यासाठी किंवा सुधारित करण्यासाठी याचा वापर करू शकतात."</string>
-    <string name="permdesc_writeCallLog" product="tv" msgid="7939219462637746280">"येणार्‍या आणि केल्या जाणार्‍या कॉलविषयीच्या डेटासह, तुमच्या Android TV डिव्हाइसचा कॉल लॉग सुधारित करण्यासाठी अॅपला अनुमती देते. दुर्भावनापूर्ण अॅप्स तुमचा कॉल लॉग मिटवण्यासाठी किंवा सुधारित करण्यासाठी याचा वापर करू शकतात."</string>
+    <string name="permdesc_writeCallLog" product="tv" msgid="7939219462637746280">"येणार्‍या आणि केल्या जाणार्‍या कॉलविषयीच्या डेटासह, तुमच्या Android TV डिव्हाइसचा कॉल लॉग सुधारित करण्यासाठी अॅपला अनुमती देते. दुर्भावनापूर्ण अ‍ॅप्स तुमचा कॉल लॉग मिटवण्यासाठी किंवा सुधारित करण्यासाठी याचा वापर करू शकतात."</string>
     <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"येणार्‍या आणि केल्या जाणार्‍या कॉलविषयीच्या डेटासह, आपल्या फोनचा कॉल लॉग सुधारित करण्यासाठी अ‍ॅप ला अनुमती देते. दुर्भावनापूर्ण अ‍ॅप्स तुमचा कॉल लॉग मिटवण्यासाठी किंवा सुधारित करण्यासाठी याचा वापर करू शकतात."</string>
     <string name="permlab_bodySensors" msgid="4683341291818520277">"शरीर सेंसर (हृदय गती मॉनिटरसारखे) अ‍ॅक्सेस करा"</string>
     <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"हृदय गती सारख्या, आपल्या शारीरिक स्थितीचे नियंत्रण करणार्‍या सेन्सरवरून डेटामध्ये प्रवेश करण्यासाठी अॅपला अनुमती देते."</string>
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ला इंटरनेट अ‍ॅक्सेस नाही"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"पर्यायांसाठी टॅप करा"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"मोबाइल नेटवर्कला इंटरनेट अॅक्सेस नाही"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"नेटवर्कला इंटरनेट अॅक्सेस नाही"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"खाजगी DNS सर्व्हर अॅक्सेस करू शकत नाही"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"कनेक्ट केले"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ला मर्यादित कनेक्टिव्हिटी आहे"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"तरीही कनेक्ट करण्यासाठी टॅप करा"</string>
@@ -1962,9 +1965,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"सेव्ह करा"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"नाही, नको"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"अपडेट करा"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"पुढे सुरू ठेवा"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"पासवर्ड"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"पत्ता"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"क्रेडिट कार्ड"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"डेबिट कार्ड"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"पेमेंट कार्ड"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"कार्ड"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"वापरकर्तानाव"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"ईमेल अॅड्रेस"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"शांत रहा आणि जवळपास निवारा शोधा."</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 4c811fd..bfe6f2b 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tiada akses Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Ketik untuk mendapatkan pilihan"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Rangkaian mudah alih tiada akses Internet"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Rangkaian tiada akses Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Pelayan DNS peribadi tidak boleh diakses"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Disambungkan"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> mempunyai kesambungan terhad"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Ketik untuk menyambung juga"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Simpan"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Tidak, terima kasih"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Kemas kini"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Teruskan"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"kata laluan"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"alamat"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kad kredit"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"kad debit"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"kad pembayaran"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"kad"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"nama pengguna"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"alamat e-mel"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Bertenang dan cari perlindungan di kawasan yang berdekatan."</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 38a33bf..d7375e2 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> တွင် အင်တာနက်အသုံးပြုခွင့် မရှိပါ"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"အခြားရွေးချယ်စရာများကိုကြည့်ရန် တို့ပါ"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"မိုဘိုင်းကွန်ရက်တွင် အင်တာနက်ချိတ်ဆက်မှု မရှိပါ"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"ကွန်ရက်တွင် အင်တာနက်အသုံးပြုခွင့် မရှိပါ"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"သီးသန့် ဒီအန်အက်စ် (DNS) ဆာဗာကို သုံး၍မရပါ။"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"ချိတ်ဆက်ထားသည်"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> တွင် ချိတ်ဆက်မှုကို ကန့်သတ်ထားသည်"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"မည်သို့ပင်ဖြစ်စေ ချိတ်ဆက်ရန် တို့ပါ"</string>
@@ -1962,9 +1965,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"သိမ်းရန်"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"မလိုပါ"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"အပ်ဒိတ်လုပ်ရန်"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"ရှေ့ဆက်ရန်"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"စကားဝှက်"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"လိပ်စာ"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ခရက်တစ်ကတ်"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"ဒက်ဘစ် ကတ်"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"ငွေပေးချေမှုကတ်"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"ကတ်"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"အသုံးပြုသူအမည်"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"အီးမေးလ်လိပ်စာ"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"စိတ်ငြိမ်ငြိမ်ထားပြီး အနီးအနားတဝိုက်တွင် ခိုနားစရာ နေရာရှာပါ။"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 2d4a5f5..3a78f79 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har ingen internettilkobling"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Trykk for å få alternativer"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobilnettverket har ingen internettilgang"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Nettverket har ingen internettilgang"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Den private DNS-tjeneren kan ikke nås"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Tilkoblet"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har begrenset tilkobling"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Trykk for å koble til likevel"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Lagre"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Nei takk"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Oppdater"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Fortsett"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"passord"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"adresse"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kredittkort"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"debetkort"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"betalingskort"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"kort"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"brukernavn"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"e-postadresse"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Hold deg rolig og søk ly i nærheten."</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index dc44d2a..d3eb0c3 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1280,6 +1280,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> को इन्टरनेटमाथि पहुँच छैन"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"विकल्पहरूका लागि ट्याप गर्नुहोस्"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"मोबाइल नेटवर्कको इन्टरनेटमाथि पहुँच छैन"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"नेटवर्कको इन्टरनेटमाथि पहुँच छैन"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"निजी DNS सर्भरमाथि पहुँच प्राप्त गर्न सकिँदैन"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"जोडियो"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> को जडान सीमित छ"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"जसरी भए पनि जडान गर्न ट्याप गर्नुहोस्"</string>
@@ -1967,9 +1970,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"सुरक्षित गर्नुहोस्"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"पर्दैन, धन्यवाद"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"अद्यावधिक गर्नुहोस्"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"जारी राख्नुहोस्"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"पासवर्ड"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"ठेगाना"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"क्रेडिट कार्ड"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"डेबिट कार्ड"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"भुक्तानी कार्ड"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"कार्ड"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"प्रयोगकर्ताको नाम"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"इमेल ठेगाना"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"शान्त रहनुहोस् र नजिकै आश्रयस्थल खोज्नुहोस्।"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 5c30c41..9300f74 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> heeft geen internettoegang"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tik voor opties"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobiel netwerk heeft geen internettoegang"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Netwerk heeft geen internettoegang"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Geen toegang tot privé-DNS-server"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Verbonden"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> heeft beperkte connectiviteit"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Tik om toch verbinding te maken"</string>
@@ -1666,14 +1669,14 @@
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Verwijderen"</string>
     <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Volume verhogen tot boven het aanbevolen niveau?\n\nAls je langere tijd op hoog volume naar muziek luistert, raakt je gehoor mogelijk beschadigd."</string>
-    <string name="accessibility_shortcut_warning_dialog_title" msgid="8404780875025725199">"Sneltoets voor toegankelijkheid gebruiken?"</string>
+    <string name="accessibility_shortcut_warning_dialog_title" msgid="8404780875025725199">"Snelkoppeling toegankelijkheid gebruiken?"</string>
     <string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Wanneer de snelkoppeling is ingeschakeld, kun je drie seconden op beide volumeknoppen drukken om een toegankelijkheidsfunctie te starten.\n\n Huidige toegankelijkheidsfunctie:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Je kunt de functie wijzigen in Instellingen &gt; Toegankelijkheid."</string>
     <string name="disable_accessibility_shortcut" msgid="627625354248453445">"Sneltoets uitschakelen"</string>
     <string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Sneltoets gebruiken"</string>
     <string name="color_inversion_feature_name" msgid="4231186527799958644">"Kleurinversie"</string>
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Kleurcorrectie"</string>
-    <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"\'Snelle link voor toegankelijkheid\' heeft <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ingeschakeld"</string>
-    <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"\'Snelle link voor toegankelijkheid\' heeft <xliff:g id="SERVICE_NAME">%1$s</xliff:g> uitgeschakeld"</string>
+    <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"\'Snelkoppeling toegankelijkheid\' heeft <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ingeschakeld"</string>
+    <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"\'Snelkoppeling toegankelijkheid\' heeft <xliff:g id="SERVICE_NAME">%1$s</xliff:g> uitgeschakeld"</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Houd beide volumetoetsen drie seconden ingedrukt om <xliff:g id="SERVICE_NAME">%1$s</xliff:g> te gebruiken"</string>
     <string name="accessibility_button_prompt_text" msgid="1176658502969738564">"Kies een service om te gebruiken wanneer je op de toegankelijkheidsknop tikt:"</string>
     <string name="accessibility_gesture_prompt_text" msgid="8259145549733019401">"Kies een service om te gebruiken met het toegankelijkheidsgebaar (veeg met twee vingers omhoog vanaf de onderkant van het scherm):"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Opslaan"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Nee, bedankt"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Updaten"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Doorgaan"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"Wachtwoord"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"Adres"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"Creditcard"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"pinpas"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"betaalkaart"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"kaart"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"gebruikersnaam"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"e-mailadres"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Blijf kalm en zoek onderdak in de buurt."</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index ac85a40..cd36d53 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ର ଇଣ୍ଟର୍ନେଟ୍ ଆକ୍ସେସ୍ ନାହିଁ"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ବିକଳ୍ପ ପାଇଁ ଟାପ୍‍ କରନ୍ତୁ"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"ମୋବାଇଲ୍ ନେଟ୍‌ୱାର୍କରେ ଇଣ୍ଟର୍ନେଟ୍ ଆକ୍ସେସ୍ ନାହିଁ"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"ନେଟ୍‌ୱାର୍କରେ ଇଣ୍ଟର୍ନେଟ୍ ଆକ୍ସେସ୍ ନାହିଁ"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"ବ୍ୟକ୍ତିଗତ DNS ସର୍ଭର୍ ଆକ୍ସେସ୍ କରିହେବ ନାହିଁ"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"ସଂଯୁକ୍ତ ହୋଇଛି"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ର ସୀମିତ ସଂଯୋଗ ଅଛି"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"ତଥାପି ଯୋଗାଯୋଗ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"ସେଭ୍‌ କରନ୍ତୁ"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"ନାଁ, ପଚାରିଥିବାରୁ ଧନ୍ୟବାଦ"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"ଅପ୍‍ଡେଟ୍‌ କରନ୍ତୁ"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"ଜାରି ରଖନ୍ତୁ"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"ପାସୱର୍ଡ୍"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"ଠିକଣା"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"କ୍ରେଡିଟ୍ କାର୍ଡ"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"ଡେବିଟ୍ କାର୍ଡ"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"ପେମେଣ୍ଟ କାର୍ଡ"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"କାର୍ଡ"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"ୟୁଜରଙ୍କ ନାମ"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"ଇମେଲ୍ ଠିକଣା"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"ଶାନ୍ତ ରୁହନ୍ତୁ ଓ ନିକଟର କୌଣସି ଏକ ଆଶ୍ରୟସ୍ଥଳ ଖୋଜନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 177c7bc..68cfc5f 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ਵਿਕਲਪਾਂ ਲਈ ਟੈਪ ਕਰੋ"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ ਕੋਲ ਇੰਟਰਨੈੱਟ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"ਨੈੱਟਵਰਕ ਕੋਲ ਇੰਟਰਨੈੱਟ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"ਨਿੱਜੀ ਡੋਮੇਨ ਨਾਮ ਪ੍ਰਣਾਲੀ (DNS) ਸਰਵਰ \'ਤੇ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"ਕਨੈਕਟ ਹੋਏ"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ਕੋਲ ਸੀਮਤ ਕਨੈਕਟੀਵਿਟੀ ਹੈ"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"ਫਿਰ ਵੀ ਕਨੈਕਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
@@ -1962,9 +1965,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"ਰੱਖਿਅਤ ਕਰੋ"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"ਨਹੀਂ ਧੰਨਵਾਦ"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"ਅੱਪਡੇਟ ਕਰੋ"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"ਜਾਰੀ ਰੱਖੋ"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"ਪਾਸਵਰਡ"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"ਪਤਾ"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ਕ੍ਰੈਡਿਟ ਕਾਰਡ"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"ਡੈਬਿਟ ਕਾਰਡ"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"ਭੁਗਤਾਨ ਕਾਰਡ"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"ਕਾਰਡ"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"ਵਰਤੋਂਕਾਰ ਨਾਮ"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"ਈਮੇਲ ਪਤਾ"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"ਸ਼ਾਂਤ ਰਹੋ ਅਤੇ ਆਸ-ਪਾਸ ਪਨਾਹ ਮੰਗੋ।"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 1f2430c..3be0900 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -307,7 +307,7 @@
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na nagrywanie dźwięku?"</string>
     <string name="permgrouplab_activityRecognition" msgid="1565108047054378642">"Aktywność fizyczna"</string>
     <string name="permgroupdesc_activityRecognition" msgid="6949472038320473478">"dostęp do aktywności fizycznej"</string>
-    <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"Zezwolić aplikacji „<xliff:g id="APP_NAME">%1$s</xliff:g>” na dostęp do aktywności fizycznej?"</string>
+    <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na dostęp do aktywności fizycznej?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Aparat"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"robienie zdjęć i nagrywanie filmów"</string>
     <string name="permgrouprequest_camera" msgid="1299833592069671756">"Zezwolić aplikacji &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; na robienie zdjęć i nagrywanie filmów?"</string>
@@ -1318,6 +1318,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nie ma dostępu do internetu"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Kliknij, by wyświetlić opcje"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Sieć komórkowa nie ma dostępu do internetu"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Sieć nie ma dostępu do internetu"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Brak dostępu do prywatnego serwera DNS"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Połączono"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ma ograniczoną łączność"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Kliknij, by mimo to nawiązać połączenie"</string>
@@ -2031,9 +2034,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Zapisz"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Nie, dziękuję"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Zaktualizuj"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Dalej"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"hasło"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"adres"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"karta kredytowa"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"karta debetowa"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"karta płatnicza"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"karta"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"nazwa użytkownika"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"adres e-mail"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Zachowaj spokój i poszukaj schronienia w pobliżu."</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 05967af..7442703 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> não tem acesso à Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toque para ver opções"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"A rede móvel não tem acesso à Internet"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"A rede não tem acesso à Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Não é possível acessar o servidor DNS privado"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Conectado"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tem conectividade limitada"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Toque para conectar mesmo assim"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Salvar"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Não, obrigado"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Atualizar"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Continuar"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"senha"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"endereço"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"cartão de crédito"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"cartão de débito"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"cartão de pagamento"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"cartão"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"nome de usuário"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"endereço de e-mail"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Fique calmo e procure um abrigo por perto."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 400d576..add12d9 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> não tem acesso à Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toque para obter mais opções"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"A rede móvel não tem acesso à Internet"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"A rede não tem acesso à Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Não é possível aceder ao servidor DNS."</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Ligado"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tem conetividade limitada."</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Toque para ligar mesmo assim."</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Guardar"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Não, obrigado"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Atualizar"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Continuar"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"palavra-passe"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"endereço"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"cartão de crédito"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"cartão de débito"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"cartão de pagamento"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"cartão"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"nome de utilizador"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"endereço de email"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Mantenha a calma e procure abrigo nas proximidades."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 05967af..7442703 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> não tem acesso à Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Toque para ver opções"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"A rede móvel não tem acesso à Internet"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"A rede não tem acesso à Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Não é possível acessar o servidor DNS privado"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Conectado"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tem conectividade limitada"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Toque para conectar mesmo assim"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Salvar"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Não, obrigado"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Atualizar"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Continuar"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"senha"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"endereço"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"cartão de crédito"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"cartão de débito"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"cartão de pagamento"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"cartão"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"nome de usuário"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"endereço de e-mail"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Fique calmo e procure um abrigo por perto."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 27e6ec0..82ec2b6 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -301,13 +301,13 @@
     <string name="permgrouprequest_storage" msgid="7885942926944299560">"Permiteți &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să acceseze fotografiile, conținutul media și fișierele de pe dispozitiv?"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Microfon"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"înregistreze sunet"</string>
-    <string name="permgrouprequest_microphone" msgid="9167492350681916038">"Pemiteți &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să înregistreze conținut audio?"</string>
+    <string name="permgrouprequest_microphone" msgid="9167492350681916038">"Pemiteți &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să înregistreze audio?"</string>
     <string name="permgrouplab_activityRecognition" msgid="1565108047054378642">"Activitate fizică"</string>
     <string name="permgroupdesc_activityRecognition" msgid="6949472038320473478">"accesați activitatea fizică"</string>
     <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"Permiteți aplicației &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să vă acceseze activitatea fizică?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Camera foto"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"fotografieze și să înregistreze videoclipuri"</string>
-    <string name="permgrouprequest_camera" msgid="1299833592069671756">"Permiteți &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să facă fotografii și să înregistreze videoclipuri?"</string>
+    <string name="permgrouprequest_camera" msgid="1299833592069671756">"Permiteți &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să fotografieze și să înregistreze video?"</string>
     <string name="permgrouplab_calllog" msgid="8798646184930388160">"Jurnale de apeluri"</string>
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"să citească și să scrie jurnalul de apeluri telefonice"</string>
     <string name="permgrouprequest_calllog" msgid="8487355309583773267">"Permiteți &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; să vă acceseze jurnalele de apeluri?"</string>
@@ -1296,6 +1296,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nu are acces la internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Atingeți pentru opțiuni"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Rețeaua mobilă nu are acces la internet"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Rețeaua nu are acces la internet"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Serverul DNS privat nu poate fi accesat"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Conectat"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> are conectivitate limitată"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Atingeți pentru a vă conecta oricum"</string>
@@ -1996,9 +1999,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Salvați"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Nu, mulțumesc"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Actualizați"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Continuați"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"parolă"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"adresă"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"card de credit"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"card de debit"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"card de plată"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"card"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"nume de utilizator"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"adresă de e-mail"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Păstrați-vă calmul și căutați un adăpost în apropiere."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 6390b95..f01de36 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1318,6 +1318,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"Сеть \"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>\" не подключена к Интернету"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Нажмите, чтобы показать варианты."</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Мобильная сеть не подключена к Интернету"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Сеть не подключена к Интернету"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Доступа к частному DNS-серверу нет."</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Подключено"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Подключение к сети \"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>\" ограничено"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Нажмите, чтобы подключиться"</string>
@@ -2031,9 +2034,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Сохранить"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Нет, спасибо"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Обновить"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Продолжить"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"Пароль"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"Адрес"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"Банковская карта"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"дебетовая карта"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"платежная карта"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"карта"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"имя пользователя"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"адрес электронной почты"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Сохраняйте спокойствие и поищите укрытие поблизости."</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index fc69d0e..6dbf502 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1276,6 +1276,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> හට අන්තර්ජාල ප්‍රවේශය නැත"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"විකල්ප සඳහා තට්ටු කරන්න"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"ජංගම ජාලවලට අන්තර්ජාල ප්‍රවේශය නැත"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"ජාලයට අන්තර්ජාල ප්‍රවේශය නැත"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"පුද්ගලික DNS සේවාදායකයට ප්‍රවේශ වීමට නොහැකිය"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"සම්බන්ධයි"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> හට සීමිත සබැඳුම් හැකියාවක් ඇත"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"කෙසේ වෙතත් ඉදිරියට යාමට තට්ටු කරන්න"</string>
@@ -1963,9 +1966,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"සුරකින්න"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"එපා ස්තූතියි"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"යාවත්කාලීන කරන්න"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"ඉදිරියට යන්න"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"මුරපදය"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"ලිපිනය"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ණය කාඩ්පත"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"හර කාඩ්පත"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"ගෙවීම් කාඩ්පත"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"කාඩ්පත"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"පරිශීලක නාමය"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"ඊ-තැපැල් ලිපිනය"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"සන්සුන්ව ඉන්න සහ අවට ඇති නවාතැන් පහසුකම් බලන්න."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 59e8b5e..18a8794 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -310,7 +310,7 @@
     <string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"Povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prístup k vašej fyzickej aktivite?"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Fotoaparát"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"fotenie a natáčanie videí"</string>
-    <string name="permgrouprequest_camera" msgid="1299833592069671756">"Povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; snímať fotky a zaznamenávať video?"</string>
+    <string name="permgrouprequest_camera" msgid="1299833592069671756">"Chcete povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; fotiť a nahrávať video?"</string>
     <string name="permgrouplab_calllog" msgid="8798646184930388160">"Zoznam hovorov"</string>
     <string name="permgroupdesc_calllog" msgid="3006237336748283775">"čítať a zapisovať do zoznamu hovorov"</string>
     <string name="permgrouprequest_calllog" msgid="8487355309583773267">"Povoliť aplikácii &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; prístup k zoznamu hovorov?"</string>
@@ -1318,6 +1318,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nemá prístup k internetu"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Klepnutím získate možnosti"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobilná sieť nemá prístup k internetu"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Sieť nemá prístup k internetu"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"K súkromnému serveru DNS sa nepodarilo získať prístup"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Pripojené"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> má obmedzené pripojenie"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Ak sa chcete aj napriek tomu pripojiť, klepnite"</string>
@@ -2031,9 +2034,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Uložiť"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Nie, vďaka"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Aktualizovať"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Pokračovať"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"heslo"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"adresa"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kreditná karta"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"debetná karta"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"platobná karta"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"karta"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"používateľské meno"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"e-mailová adresa"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Zachovajte pokoj a vyhľadajte úkryt v okolí."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index c49d5ff..40d0dde 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1318,6 +1318,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"Omrežje <xliff:g id="NETWORK_SSID">%1$s</xliff:g> nima dostopa do interneta"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dotaknite se za možnosti"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobilno omrežje nima dostopa do interneta"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Omrežje nima dostopa do interneta"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Do zasebnega strežnika DNS ni mogoče dostopati"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Povezava je vzpostavljena"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Povezljivost omrežja <xliff:g id="NETWORK_SSID">%1$s</xliff:g> je omejena"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Dotaknite se, da kljub temu vzpostavite povezavo"</string>
@@ -2031,9 +2034,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Shrani"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Ne, hvala"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Posodobi"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Naprej"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"geslo"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"naslov"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kreditno kartico"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"debetna kartica"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"plačilna kartica"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"kartica"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"uporabniško ime"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"e-poštni naslov"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Ostanite mirni in poiščite zavetje v bližini."</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 045c7d5..ee46d3b 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nuk ka qasje në internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Trokit për opsionet"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Rrjeti celular nuk ka qasje në internet"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Rrjeti nuk ka qasje në internet"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Serveri privat DNS nuk mund të qaset"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Lidhur"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ka lidhshmëri të kufizuar"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Trokit për t\'u lidhur gjithsesi"</string>
@@ -1962,9 +1965,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Ruaj"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Jo, faleminderit"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Përditëso"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Vazhdo"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"fjalëkalimi"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"adresa"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"karta e kreditit"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"kartë debiti"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"kartë pagese"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"kartë"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"emri i përdoruesit"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"adresa e mail-it"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Qëndro i qetë dhe kërko strehim në afërsi."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 0d8acc6..7fd7353 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1296,6 +1296,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> нема приступ интернету"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Додирните за опције"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Мобилна мрежа нема приступ интернету"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Мрежа нема приступ интернету"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Приступ приватном DNS серверу није успео"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Повезано је"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> има ограничену везу"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Додирните да бисте се ипак повезали"</string>
@@ -1996,9 +1999,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Сачувај"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Не, хвала"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Ажурирај"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Настави"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"лозинка"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"адреса"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"кредитна картица"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"дебитна картица"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"платна картица"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"картица"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"корисничко име"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"имејл адреса"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Останите мирни и потражите склониште у околини."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index dba5ebb..b8da1b6 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har ingen internetanslutning"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Tryck för alternativ"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobilnätverket har ingen internetanslutning"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Nätverket har ingen internetanslutning"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Det går inte att komma åt den privata DNS-servern."</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Ansluten"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har begränsad anslutning"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Tryck för att ansluta ändå"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Spara"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Nej tack"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Uppdatera"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Fortsätt"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"lösenordet"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"adressen"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kreditkortet"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"bankkort"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"kontokort"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"kort"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"användarnamn"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"e-postadress"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Håll dig lugn och sök skydd i närheten."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 89e3231..88221b6 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> haina uwezo wa kufikia intaneti"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Gusa ili upate chaguo"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mtandao wa simu hauna uwezo wa kufikia intaneti"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Mtandao hauna uwezo wa kufikia intaneti"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Seva ya faragha ya DNS haiwezi kufikiwa"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Imeunganisha"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ina muunganisho unaofikia huduma chache."</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Gusa ili uunganishe tu"</string>
@@ -1349,7 +1352,7 @@
     <string name="dlg_ok" msgid="7376953167039865701">"Sawa"</string>
     <string name="usb_charging_notification_title" msgid="1595122345358177163">"Unachaji kifaa hiki kupitia USB"</string>
     <string name="usb_supplying_notification_title" msgid="4631045789893086181">"Inachaji kifaa kilichounganishwa kupitia USB"</string>
-    <string name="usb_mtp_notification_title" msgid="4238227258391151029">"Umewasha hali ya uhamishaji wa faili kupitia USB"</string>
+    <string name="usb_mtp_notification_title" msgid="4238227258391151029">"Umewasha uhamishaji wa faili kupitia USB"</string>
     <string name="usb_ptp_notification_title" msgid="5425857879922006878">"Umewasha hali ya PTP kupitia USB"</string>
     <string name="usb_tether_notification_title" msgid="3716143122035802501">"Umewasha hali ya kusambaza mtandao ukitumia USB"</string>
     <string name="usb_midi_notification_title" msgid="5356040379749154805">"Umewasha hali ya MIDI kupitia USB"</string>
@@ -1666,14 +1669,14 @@
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ondoa"</string>
     <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Ungependa kupandisha sauti zaidi ya kiwango kinachopendekezwa?\n\nKusikiliza kwa sauti ya juu kwa muda mrefu kunaweza kuharibu uwezo wako wa kusikia."</string>
-    <string name="accessibility_shortcut_warning_dialog_title" msgid="8404780875025725199">"Ungependa Kutumia Njia ya Mkato ya Zana za walio na matatizo ya kuona au kusikia?"</string>
-    <string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Unapowasha kipengele cha njia ya mkato, hatua ya kubonyeza vitufe vyote viwili vya sauti kwa dakika 3 itafungua kipengele cha zana za walio na matatizo ya kuona au kusikia.\n\n Kipengele kilichopo cha zana za walio na matatizo ya kuona au kusikia:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Unaweza kubadilisha kipengele hiki katika Mipangilio &gt; Zana za walio na matatizo ya kuona au kusikia."</string>
+    <string name="accessibility_shortcut_warning_dialog_title" msgid="8404780875025725199">"Ungependa kutumia njia ya mkato ya ufikivu?"</string>
+    <string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Unapowasha kipengele cha njia ya mkato, hatua ya kubonyeza vitufe vyote viwili vya sauti kwa dakika 3 itafungua kipengele cha ufikivu.\n\n Kipengele cha ufikivu kilichopo kwa sasa:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Unaweza kubadilisha kipengele hiki katika Mipangilio &gt; Zana za ufikivu."</string>
     <string name="disable_accessibility_shortcut" msgid="627625354248453445">"Zima kipengele cha Njia ya Mkato"</string>
     <string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Tumia Njia ya Mkato"</string>
     <string name="color_inversion_feature_name" msgid="4231186527799958644">"Ugeuzaji rangi"</string>
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Usahihishaji wa rangi"</string>
-    <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Njia ya mkato ya zana za walio na matatizo ya kuona au kusikia imewasha <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Njia ya mkato ya zana za walio na matatizo ya kuona au kusikia imezima <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Njia ya mkato ya ufikivu imewasha <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Njia ya mkato ya ufikivu imezima <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Bonyeza na ushikilie vitufe vyote viwili vya sauti kwa sekunde tatu ili utumie <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_button_prompt_text" msgid="1176658502969738564">"Chagua huduma ya kutumia unapogusa kitufe cha ufikivu:"</string>
     <string name="accessibility_gesture_prompt_text" msgid="8259145549733019401">"Chagua huduma ya kutumia pamoja na ishara ya ufikivu (telezesha vidole viwili kutoka chini kwenda juu kwenye skrini):"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Hifadhi"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Hapana, asante"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Sasisha"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Endelea"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"nenosiri"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"anwani"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kadi ya mikopo"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"kadi ya malipo"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"kadi ya malipo"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"kadi"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"jina la mtumiaji"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"anwani ya barua pepe"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Tulia na utafute hifadhi ya karibu."</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 0ed1421..6c35423 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> நெட்வொர்க்கிற்கு இணைய அணுகல் இல்லை"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"விருப்பங்களுக்கு, தட்டவும்"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"மொபைல் நெட்வொர்க்கிற்கு இணைய அணுகல் இல்லை"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"நெட்வொர்க்கிற்கு இணைய அணுகல் இல்லை"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"தனிப்பட்ட DNS சேவையகத்தை அணுக இயலாது"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"இணைக்கப்பட்டது"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> வரம்பிற்கு உட்பட்ட இணைப்புநிலையைக் கொண்டுள்ளது"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"எப்படியேனும் இணைப்பதற்குத் தட்டவும்"</string>
@@ -1962,9 +1965,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"சேமி"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"வேண்டாம்"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"புதுப்பி"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"தொடர்க"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"கடவுச்சொல்"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"முகவரி"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"கிரெடிட் கார்டு"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"டெபிட் கார்டு"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"பேமெண்ட் கார்டு"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"கார்டு"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"பயனர்பெயர்"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"மின்னஞ்சல் முகவரி"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"பதட்டப்படாதீர்கள், அருகில் ஏதேனும் பாதுகாப்பான இடம் உள்ளதா எனப் பாருங்கள்."</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 72b83c4..7e91460 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>కి ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ఎంపికల కోసం నొక్కండి"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"మొబైల్ నెట్‌వర్క్‌కు ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"నెట్‌వర్క్‌కు ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"ప్రైవేట్ DNS సర్వర్‌ను యాక్సెస్ చేయడం సాధ్యపడదు"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"కనెక్ట్ చేయబడింది"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> పరిమిత కనెక్టివిటీని కలిగి ఉంది"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"ఏదేమైనా కనెక్ట్ చేయడానికి నొక్కండి"</string>
@@ -1962,9 +1965,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"సేవ్ చేయి"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"వద్దు, ధన్యవాదాలు"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"అప్‌డేట్ చేయి"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"కొనసాగించు"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"పాస్‌వర్డ్"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"చిరునామా"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"క్రెడిట్ కార్డ్"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"డెబిట్ కార్డ్"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"చెల్లింపు కార్డ్"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"కార్డ్"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"వినియోగదారు పేరు"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"ఇమెయిల్ చిరునామా"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"ప్రశాంతంగా ఉండండి మరియు దగ్గర్లో తలదాచుకోండి."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index caaa32d..fd77532 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1234,7 +1234,7 @@
     <string name="volume_unknown" msgid="1400219669770445902">"ระดับเสียง"</string>
     <string name="volume_icon_description_bluetooth" msgid="6538894177255964340">"ระดับบลูทูธ"</string>
     <string name="volume_icon_description_ringer" msgid="3326003847006162496">"ระดับเสียงเรียกเข้า"</string>
-    <string name="volume_icon_description_incall" msgid="8890073218154543397">"ปริมาณการโทร"</string>
+    <string name="volume_icon_description_incall" msgid="8890073218154543397">"ระดับเสียงการโทร"</string>
     <string name="volume_icon_description_media" msgid="4217311719665194215">"ระดับเสียงของสื่อ"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"ระดับเสียงของการแจ้งเตือน"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"เสียงเรียกเข้าเริ่มต้น"</string>
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> เข้าถึงอินเทอร์เน็ตไม่ได้"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"แตะเพื่อดูตัวเลือก"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"เครือข่ายมือถือไม่มีการเข้าถึงอินเทอร์เน็ต"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"เครือข่ายไม่มีการเข้าถึงอินเทอร์เน็ต"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"เข้าถึงเซิร์ฟเวอร์ DNS ไม่ได้"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"เชื่อมต่อแล้ว"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> มีการเชื่อมต่อจำกัด"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"แตะเพื่อเชื่อมต่อ"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"บันทึก"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"ไม่เป็นไร"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"อัปเดต"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"ทำต่อ"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"รหัสผ่าน"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"ที่อยู่"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"บัตรเครดิต"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"บัตรเดบิต"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"บัตรสำหรับชำระเงิน"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"บัตร"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"ชื่อผู้ใช้"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"ที่อยู่อีเมล"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"ทำใจให้สงบและหาที่กำบังในบริเวณใกล้เคียง"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 01cf28f..3e71d77 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"Walang access sa internet ang <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"I-tap para sa mga opsyon"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Walang access sa internet ang mobile network"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Walang access sa internet ang network"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Hindi ma-access ang pribadong DNS server"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Nakakonekta"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Limitado ang koneksyon ng <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"I-tap para kumonekta pa rin"</string>
@@ -1666,8 +1669,8 @@
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Alisin"</string>
     <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Lakasan ang volume nang lagpas sa inirerekomendang antas?\n\nMaaaring mapinsala ng pakikinig sa malakas na volume sa loob ng mahahabang panahon ang iyong pandinig."</string>
-    <string name="accessibility_shortcut_warning_dialog_title" msgid="8404780875025725199">"Gagamitin ang Shortcut sa Pagiging Naa-access?"</string>
-    <string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Kapag naka-on ang shortcut, magsisimula ang isang feature ng pagiging naa-access kapag pinindot ang parehong button ng volume sa loob ng 3 segundo.\n\n Kasalukuyang feature ng pagiging naa-access:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Maaari mong baguhin ang feature sa Mga Setting &gt; Pagiging Naa-access."</string>
+    <string name="accessibility_shortcut_warning_dialog_title" msgid="8404780875025725199">"Gagamitin ang Shortcut sa Pagiging Accessible?"</string>
+    <string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Kapag naka-on ang shortcut, magsisimula ang isang feature ng pagiging naa-access kapag pinindot ang parehong button ng volume sa loob ng 3 segundo.\n\n Kasalukuyang feature ng pagiging naa-access:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Maaari mong baguhin ang feature sa Mga Setting &gt; Pagiging Accessible."</string>
     <string name="disable_accessibility_shortcut" msgid="627625354248453445">"I-off ang Shortcut"</string>
     <string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Gamitin ang Shortcut"</string>
     <string name="color_inversion_feature_name" msgid="4231186527799958644">"Pag-invert ng Kulay"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"I-save"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Hindi, salamat na lang"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"I-update"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Magpatuloy"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"password"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"address"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"credit card"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"debit card"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"card sa pagbabayad"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"card"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"username"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"email address"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Manatiling kalmado at maghanap ng matutuluyan sa malapit."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index d3e9d93..8a63348 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ağının internet bağlantısı yok"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Seçenekler için dokunun"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobil ağın internet bağlantısı yok"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Ağın internet bağlantısı yok"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Gizli DNS sunucusuna erişilemiyor"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Bağlandı"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> sınırlı bağlantıya sahip"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Yine de bağlanmak için dokunun"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Kaydet"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Hayır, teşekkürler"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Güncelle"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Devam"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"şifre"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"adres"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kredi kartı"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"banka kartı"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"ödeme kartı"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"kart"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"kullanıcı adı"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"e-posta adresi"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Sakin olun ve yakınlarda sığınabileceğiniz bir yer bulun."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 88350a2..3d7358e 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1318,6 +1318,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"Мережа <xliff:g id="NETWORK_SSID">%1$s</xliff:g> не має доступу до Інтернету"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Торкніться, щоб відкрити опції"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Мобільна мережа не має доступу до Інтернету"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Мережа не має доступу до Інтернету"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Немає доступу до приватного DNS-сервера"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Підключено"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Підключення до мережі <xliff:g id="NETWORK_SSID">%1$s</xliff:g> обмежено"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Натисніть, щоб усе одно підключитися"</string>
@@ -1714,14 +1717,14 @@
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Вилучити"</string>
     <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Збільшити гучність понад рекомендований рівень?\n\nЯкщо слухати надто гучну музику тривалий час, можна пошкодити слух."</string>
-    <string name="accessibility_shortcut_warning_dialog_title" msgid="8404780875025725199">"Використовувати ярлик спеціальних можливостей?"</string>
+    <string name="accessibility_shortcut_warning_dialog_title" msgid="8404780875025725199">"Використовувати швидке ввімкнення?"</string>
     <string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Коли ярлик увімкнено, після натискання обох клавіш гучності й утримування їх протягом 3 секунд увімкнеться функція спеціальних можливостей.\n\n Поточна функція спеціальних можливостей:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Цю функцію можна змінити в меню \"Налаштування\" &gt; \"Спеціальні можливості\"."</string>
     <string name="disable_accessibility_shortcut" msgid="627625354248453445">"Вимкнути ярлик"</string>
     <string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"Використовувати ярлик"</string>
     <string name="color_inversion_feature_name" msgid="4231186527799958644">"Інверсія кольорів"</string>
     <string name="color_correction_feature_name" msgid="6779391426096954933">"Корекція кольорів"</string>
-    <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Ярлик спеціальних можливостей увімкнув <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Ярлик спеціальних можливостей вимкнув <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"Сервіс <xliff:g id="SERVICE_NAME">%1$s</xliff:g> увімкнено"</string>
+    <string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"Сервіс <xliff:g id="SERVICE_NAME">%1$s</xliff:g> вимкнено"</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Щоб скористатися службою <xliff:g id="SERVICE_NAME">%1$s</xliff:g>, утримуйте обидві клавіші гучності впродовж трьох секунд"</string>
     <string name="accessibility_button_prompt_text" msgid="1176658502969738564">"Виберіть сервіс для кнопки спеціальних можливостей:"</string>
     <string name="accessibility_gesture_prompt_text" msgid="8259145549733019401">"Виберіть сервіс для жесту спеціальних можливостей (проведення двома пальцями знизу вгору):"</string>
@@ -2031,9 +2034,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Зберегти"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Ні, дякую"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Оновити"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Продовжити"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"пароль"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"адреса"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"кредитна картка"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"дебетова картка"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"платіжна картка"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"картка"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"ім’я користувача"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"електронна адреса"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Не хвилюйтеся та знайдіть прихисток поблизу."</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index e5015ea..97660b4 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> کو انٹرنیٹ تک رسائی حاصل نہیں ہے"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"اختیارات کیلئے تھپتھپائیں"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"موبائل نیٹ ورک کو انٹرنیٹ تک رسائی حاصل نہیں ہے"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"نیٹ ورک کو انٹرنیٹ تک رسائی حاصل نہیں ہے"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"‏نجی DNS سرور تک رسائی حاصل نہیں کی جا سکی"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"منسلک ہے"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> کی کنیکٹوٹی محدود ہے"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"بہر حال منسلک کرنے کے لیے تھپتھپائیں"</string>
@@ -1962,9 +1965,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"محفوظ کریں"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"نہیں، شکریہ"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"اپ ڈیٹ کریں"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"جاری رکھیں"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"پاس ورڈ"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"پتہ"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"کریڈٹ کارڈ"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"ڈیبٹ کارڈ"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"ادائیگی کارڈ"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"کارڈ"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"صارف نام"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"ای میل پتہ"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"پُرسکون رہیں اور قریبی پناہ حاصل کریں۔"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 8899747..1f70155 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nomli tarmoqda internetga ruxsati yoʻq"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Variantlarni ko‘rsatish uchun bosing"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mobil tarmoq internetga ulanmagan"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Tarmoq internetga ulanmagan"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Xususiy DNS server ishlamayapti"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Ulandi"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nomli tarmoqda aloqa cheklangan"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Baribir ulash uchun bosing"</string>
@@ -1962,9 +1965,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Saqlash"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Kerak emas"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Yangilash"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Davom etish"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"parol"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"manzil"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"kredit karta"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"debet karta"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"toʻlov kartasi"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"bildirgi"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"foydalanuvchi nomi"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"email manzili"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Tinchlaning va yaqin-atrofdan boshpana qidiring."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index fc8994e..dc9076f 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> không có quyền truy cập Internet"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Nhấn để biết tùy chọn"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Mạng di động không có quyền truy cập Internet"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Mạng không có quyền truy cập Internet"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Không thể truy cập máy chủ DNS riêng tư"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Đã kết nối"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> có khả năng kết nối giới hạn"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Nhấn để tiếp tục kết nối"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Lưu"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Không, cảm ơn"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Cập nhật"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Tiếp tục"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"mật khẩu"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"địa chỉ"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"thẻ tín dụng"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"thẻ ghi nợ"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"thẻ thanh toán"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"thẻ"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"tên người dùng"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"địa chỉ email"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Hãy bình tĩnh và tìm kiếm nơi trú ẩn gần đó."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 56d8153..8ab182e 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 无法访问互联网"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"点按即可查看相关选项"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"此移动网络无法访问互联网"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"此网络无法访问互联网"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"无法访问私人 DNS 服务器"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"已连接"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 的连接受限"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"点按即可继续连接"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"保存"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"不用了"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"更新"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"继续"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"密码"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"地址"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"信用卡"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"借记卡"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"支付卡"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"卡片"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"用户名"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"电子邮件地址"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"请保持冷静,并寻找附近的避难地点。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index c8360aa..d318764 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>未有連接至互聯網"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"輕按即可查看選項"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"流動網絡並未連接互聯網"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"網絡並未連接互聯網"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"無法存取私人 DNS 伺服器"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"已連接"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>連線受限"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"仍要輕按以連結至此網絡"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"儲存"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"不用了,謝謝"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"更新"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"繼續"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"密碼"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"地址"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"信用卡"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"扣帳卡"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"付款卡"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"卡"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"使用者名稱"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"電郵地址"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"請保持冷靜,並尋找附近的避難所。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 23b68e1..cd787c0 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 沒有網際網路連線"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"輕觸即可查看選項"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"這個行動網路沒有網際網路連線"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"這個網路沒有網際網路連線"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"無法存取私人 DNS 伺服器"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"已連線"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 的連線能力受限"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"輕觸即可繼續連線"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"儲存"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"不用了,謝謝"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"更新"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"繼續"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"密碼"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"地址"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"信用卡"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"簽帳金融卡"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"付款卡"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"卡片"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"使用者名稱"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"電子郵件地址"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"請保持冷靜並尋找附近的避難地點。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index dac7c10..45bda9e 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1274,6 +1274,9 @@
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"I-<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ayinakho ukufinyelela kwe-inthanethi"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Thepha ukuze uthole izinketho"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"Inethiwekhi yeselula ayinakho ukufinyelela kwe-inthanethi"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"Inethiwekhi ayinakho ukufinyelela kwenethiwekhi"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"Iseva eyimfihlo ye-DNS ayikwazi ukufinyelelwa"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Kuxhunyiwe"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"I-<xliff:g id="NETWORK_SSID">%1$s</xliff:g> inokuxhumeka okukhawulelwe"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Thepha ukuze uxhume noma kunjalo"</string>
@@ -1961,9 +1964,13 @@
     <string name="autofill_save_yes" msgid="6398026094049005921">"Londoloza"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"Cha ngiyabonga"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"Buyekeza"</string>
+    <string name="autofill_continue_yes" msgid="7473570809545975068">"Qhubeka"</string>
     <string name="autofill_save_type_password" msgid="5288448918465971568">"iphasiwedi"</string>
     <string name="autofill_save_type_address" msgid="4936707762193009542">"ikheli"</string>
     <string name="autofill_save_type_credit_card" msgid="7127694776265563071">"ikhadi lesikweletu"</string>
+    <string name="autofill_save_type_debit_card" msgid="177366134636469277">"ikhaddi lasebhange"</string>
+    <string name="autofill_save_type_payment_card" msgid="446631844461198737">"ikhadi lokukhokha"</string>
+    <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"ikhadi"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"igama lomsebenzisi"</string>
     <string name="autofill_save_type_email_address" msgid="5752949432129262174">"ikheli le-imeyili"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Hlala ubeke umoya phansi uphinde ufune ukukhuselwa eduze."</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index eaf93eb..9ca98c5 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3705,7 +3705,7 @@
          name is separated by comma.
          Example: "com.android.phone,com.android.stk,com.android.providers.telephony"
      -->
-    <string name="config_telephonyPackages" translatable="false">"com.android.phone,com.android.stk,com.android.providers.telephony,com.android.ons"</string>
+    <string name="config_telephonyPackages" translatable="false">"com.android.phone,com.android.stk,com.android.providers.telephony,com.android.ons,com.android.cellbroadcastservice"</string>
 
     <!-- The package name for the default system wifi app.
          This package must be trusted, as it has the permissions to control wifi
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d88178d..585c4bb 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3440,6 +3440,15 @@
     <!-- A notification is shown when the user connects to a Wi-Fi network and the system detects that that network has no Internet access. This is the notification's message. -->
     <string name="wifi_no_internet_detailed">Tap for options</string>
 
+    <!-- A notification is shown when the user connects to a mobile network without internet access. This is the notification's title. -->
+    <string name="mobile_no_internet">Mobile network has no internet access</string>
+
+    <!-- A notification is shown when the user connects to a non-mobile and non-wifi network without internet access. This is the notification's title. -->
+    <string name="other_networks_no_internet">Network has no internet access</string>
+
+    <!-- A notification is shown when connected network without internet due to private dns validation failed. This is the notification's message. [CHAR LIMIT=NONE] -->
+    <string name="private_dns_broken_detailed">Private DNS server cannot be accessed</string>
+
     <!-- A notification is shown after the user logs in to a captive portal network, to indicate that the network should now have internet connectivity. This is the message of notification. [CHAR LIMIT=50] -->
     <string name="captive_portal_logged_in_detailed">Connected</string>
     <!-- A notification is shown when the user connects to a network that doesn't have access to some services (e.g. Push notifications may not work). This is the notification's title. [CHAR LIMIT=50] -->
@@ -5431,4 +5440,6 @@
     <!-- ChooserActivity - Alphabetically sorted apps list label. [CHAR LIMIT=NONE] -->
     <string name="chooser_all_apps_button_label">Apps list</string>
 
+    <!-- Prompt for the USB device resolver dialog with warning text for USB device dialogs.  [CHAR LIMIT=200] -->
+    <string name="usb_device_resolve_prompt_warn">This app has not been granted record permission but could capture audio through this USB device.</string>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e2f57fd..1313912 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -593,9 +593,12 @@
   <java-symbol type="string" name="menu_space_shortcut_label" />
   <java-symbol type="string" name="menu_shift_shortcut_label" />
   <java-symbol type="string" name="menu_sym_shortcut_label" />
+  <java-symbol type="string" name="mobile_no_internet" />
   <java-symbol type="string" name="notification_title" />
+  <java-symbol type="string" name="other_networks_no_internet" />
   <java-symbol type="string" name="permission_request_notification_with_subtitle" />
   <java-symbol type="string" name="prepend_shortcut_label" />
+  <java-symbol type="string" name="private_dns_broken_detailed" />
   <java-symbol type="string" name="paste_as_plain_text" />
   <java-symbol type="string" name="replace" />
   <java-symbol type="string" name="undo" />
@@ -3873,4 +3876,6 @@
 
   <java-symbol type="bool" name="config_showBuiltinWirelessChargingAnim" />
 
+  <java-symbol type="string" name="usb_device_resolve_prompt_warn" />
+
 </resources>
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index f71c8b0..2d1c61c 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -90,7 +90,7 @@
     <shortcode country="cz" premium="9\\d{6,7}" free="116\\d{3}" />
 
     <!-- Germany: 4-5 digits plus 1232xxx (premium codes from http://www.vodafone.de/infofaxe/537.pdf and http://premiumdienste.eplus.de/pdf/kodex.pdf), plus EU. To keep the premium regex from being too large, it only includes payment processors that have been used by SMS malware, with the regular pattern matching the other premium short codes. -->
-    <shortcode country="de" pattern="\\d{4,5}|1232\\d{3}" premium="11(?:111|833)|1232(?:013|021|060|075|286|358)|118(?:44|80|86)|20[25]00|220(?:21|22|88|99)|221(?:14|21)|223(?:44|53|77)|224[13]0|225(?:20|59|90)|226(?:06|10|20|26|30|40|56|70)|227(?:07|33|39|66|76|78|79|88|99)|228(?:08|11|66|77)|23300|30030|3[12347]000|330(?:33|55|66)|33(?:233|331|366|533)|34(?:34|567)|37000|40(?:040|123|444|[3568]00)|41(?:010|414)|44(?:000|044|344|44[24]|544)|50005|50100|50123|50555|51000|52(?:255|783)|54(?:100|2542)|55(?:077|[24]00|222|333|55|[12369]55)|56(?:789|886)|60800|6[13]000|66(?:[12348]66|566|766|777|88|999)|68888|70(?:07|123|777)|76766|77(?:007|070|222|444|[567]77)|80(?:008|123|888)|82(?:002|[378]00|323|444|472|474|488|727)|83(?:005|[169]00|333|830)|84(?:141|300|32[34]|343|488|499|777|888)|85888|86(?:188|566|640|644|650|677|868|888)|870[24]9|871(?:23|[49]9)|872(?:1[0-8]|49|99)|87499|875(?:49|55|99)|876(?:0[1367]|1[1245678]|54|99)|877(?:00|99)|878(?:15|25|3[567]|8[12])|87999|880(?:08|44|55|77|99)|88688|888(?:03|10|8|89)|8899|90(?:009|999)|99999" free="116\\d{3}|81214|81215|47529|70296|83782|3011|73240" />
+    <shortcode country="de" pattern="\\d{4,5}|1232\\d{3}" premium="11(?:111|833)|1232(?:013|021|060|075|286|358)|118(?:44|80|86)|20[25]00|220(?:21|22|88|99)|221(?:14|21)|223(?:44|53|77)|224[13]0|225(?:20|59|90)|226(?:06|10|20|26|30|40|56|70)|227(?:07|33|39|66|76|78|79|88|99)|228(?:08|11|66|77)|23300|30030|3[12347]000|330(?:33|55|66)|33(?:233|331|366|533)|34(?:34|567)|37000|40(?:040|123|444|[3568]00)|41(?:010|414)|44(?:000|044|344|44[24]|544)|50005|50100|50123|50555|51000|52(?:255|783)|54(?:100|2542)|55(?:077|[24]00|222|333|55|[12369]55)|56(?:789|886)|60800|6[13]000|66(?:[12348]66|566|766|777|88|999)|68888|70(?:07|123|777)|76766|77(?:007|070|222|444|[567]77)|80(?:008|123|888)|82(?:002|[378]00|323|444|472|474|488|727)|83(?:005|[169]00|333|830)|84(?:141|300|32[34]|343|488|499|777|888)|85888|86(?:188|566|640|644|650|677|868|888)|870[24]9|871(?:23|[49]9)|872(?:1[0-8]|49|99)|87499|875(?:49|55|99)|876(?:0[1367]|1[1245678]|54|99)|877(?:00|99)|878(?:15|25|3[567]|8[12])|87999|880(?:08|44|55|77|99)|88688|888(?:03|10|8|89)|8899|90(?:009|999)|99999" free="116\\d{3}|81214|81215|47529|70296|83782|3011|73240|72438" />
 
     <!-- Denmark: see http://iprs.webspacecommerce.com/Denmark-Premium-Rate-Numbers -->
     <shortcode country="dk" pattern="\\d{4,5}" premium="1\\d{3}" free="116\\d{3}|4665" />
diff --git a/core/tests/coretests/src/android/app/NotificationHistoryTest.java b/core/tests/coretests/src/android/app/NotificationHistoryTest.java
new file mode 100644
index 0000000..08595bb
--- /dev/null
+++ b/core/tests/coretests/src/android/app/NotificationHistoryTest.java
@@ -0,0 +1,232 @@
+/*
+ * 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.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.NotificationHistory.HistoricalNotification;
+import android.graphics.drawable.Icon;
+import android.os.Parcel;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class NotificationHistoryTest {
+
+    private HistoricalNotification getHistoricalNotification(int index) {
+        return getHistoricalNotification("package" + index, index);
+    }
+
+    private HistoricalNotification getHistoricalNotification(String packageName, int index) {
+        String expectedChannelName = "channelName" + index;
+        String expectedChannelId = "channelId" + index;
+        int expectedUid = 1123456 + index;
+        int expectedUserId = 11 + index;
+        long expectedPostTime = 987654321 + index;
+        String expectedTitle = "title" + index;
+        String expectedText = "text" + index;
+        Icon expectedIcon = Icon.createWithResource(InstrumentationRegistry.getContext(),
+                index);
+
+        return new HistoricalNotification.Builder()
+                .setPackage(packageName)
+                .setChannelName(expectedChannelName)
+                .setChannelId(expectedChannelId)
+                .setUid(expectedUid)
+                .setUserId(expectedUserId)
+                .setPostedTimeMs(expectedPostTime)
+                .setTitle(expectedTitle)
+                .setText(expectedText)
+                .setIcon(expectedIcon)
+                .build();
+    }
+
+    @Test
+    public void testHistoricalNotificationBuilder() {
+        String expectedPackage = "package";
+        String expectedChannelName = "channelName";
+        String expectedChannelId = "channelId";
+        int expectedUid = 1123456;
+        int expectedUserId = 11;
+        long expectedPostTime = 987654321;
+        String expectedTitle = "title";
+        String expectedText = "text";
+        Icon expectedIcon = Icon.createWithResource(InstrumentationRegistry.getContext(),
+                android.R.drawable.btn_star);
+
+        HistoricalNotification n = new HistoricalNotification.Builder()
+                .setPackage(expectedPackage)
+                .setChannelName(expectedChannelName)
+                .setChannelId(expectedChannelId)
+                .setUid(expectedUid)
+                .setUserId(expectedUserId)
+                .setPostedTimeMs(expectedPostTime)
+                .setTitle(expectedTitle)
+                .setText(expectedText)
+                .setIcon(expectedIcon)
+                .build();
+
+        assertThat(n.getPackage()).isEqualTo(expectedPackage);
+        assertThat(n.getChannelName()).isEqualTo(expectedChannelName);
+        assertThat(n.getChannelId()).isEqualTo(expectedChannelId);
+        assertThat(n.getUid()).isEqualTo(expectedUid);
+        assertThat(n.getUserId()).isEqualTo(expectedUserId);
+        assertThat(n.getPostedTimeMs()).isEqualTo(expectedPostTime);
+        assertThat(n.getTitle()).isEqualTo(expectedTitle);
+        assertThat(n.getText()).isEqualTo(expectedText);
+        assertThat(expectedIcon.sameAs(n.getIcon())).isTrue();
+    }
+
+    @Test
+    public void testAddNotificationToWrite() {
+        NotificationHistory history = new NotificationHistory();
+        HistoricalNotification n = getHistoricalNotification(0);
+        HistoricalNotification n2 = getHistoricalNotification(1);
+
+        history.addNotificationToWrite(n2);
+        history.addNotificationToWrite(n);
+
+        assertThat(history.getNotificationsToWrite().size()).isEqualTo(2);
+        assertThat(history.getNotificationsToWrite().get(0)).isSameAs(n2);
+        assertThat(history.getNotificationsToWrite().get(1)).isSameAs(n);
+        assertThat(history.getHistoryCount()).isEqualTo(2);
+    }
+
+    @Test
+    public void testPoolStringsFromNotifications() {
+        NotificationHistory history = new NotificationHistory();
+
+        List<String> expectedStrings = new ArrayList<>();
+        for (int i = 1; i <= 10; i++) {
+            HistoricalNotification n = getHistoricalNotification(i);
+            expectedStrings.add(n.getPackage());
+            expectedStrings.add(n.getChannelName());
+            expectedStrings.add(n.getChannelId());
+            history.addNotificationToWrite(n);
+        }
+
+        history.poolStringsFromNotifications();
+
+        assertThat(history.getPooledStringsToWrite().length).isEqualTo(expectedStrings.size());
+        String previous = null;
+        for (String actual : history.getPooledStringsToWrite()) {
+            assertThat(expectedStrings).contains(actual);
+
+            if (previous != null) {
+                assertThat(actual).isGreaterThan(previous);
+            }
+            previous = actual;
+        }
+    }
+
+    @Test
+    public void testAddPooledStrings() {
+        NotificationHistory history = new NotificationHistory();
+
+        List<String> expectedStrings = new ArrayList<>();
+        for (int i = 1; i <= 10; i++) {
+            HistoricalNotification n = getHistoricalNotification(i);
+            expectedStrings.add(n.getPackage());
+            expectedStrings.add(n.getChannelName());
+            expectedStrings.add(n.getChannelId());
+            history.addNotificationToWrite(n);
+        }
+
+        history.addPooledStrings(expectedStrings);
+
+        String[] actualStrings = history.getPooledStringsToWrite();
+        assertThat(actualStrings.length).isEqualTo(expectedStrings.size());
+        String previous = null;
+        for (String actual : actualStrings) {
+            assertThat(expectedStrings).contains(actual);
+
+            if (previous != null) {
+                assertThat(actual).isGreaterThan(previous);
+            }
+            previous = actual;
+        }
+    }
+
+    @Test
+    public void testRemoveNotificationsFromWrite() {
+        NotificationHistory history = new NotificationHistory();
+
+        List<HistoricalNotification> postRemoveExpectedEntries = new ArrayList<>();
+        List<String> postRemoveExpectedStrings = new ArrayList<>();
+        for (int i = 1; i <= 10; i++) {
+            HistoricalNotification n =
+                    getHistoricalNotification((i % 2 == 0) ? "pkgEven" : "pkgOdd", i);
+
+            if (i % 2 == 0) {
+                postRemoveExpectedStrings.add(n.getPackage());
+                postRemoveExpectedStrings.add(n.getChannelName());
+                postRemoveExpectedStrings.add(n.getChannelId());
+                postRemoveExpectedEntries.add(n);
+            }
+
+            history.addNotificationToWrite(n);
+        }
+
+        history.poolStringsFromNotifications();
+
+        assertThat(history.getNotificationsToWrite().size()).isEqualTo(10);
+        // 2 package names and 10 * 2 unique channel names and ids
+        assertThat(history.getPooledStringsToWrite().length).isEqualTo(22);
+
+        history.removeNotificationsFromWrite("pkgOdd");
+
+
+        // 1 package names and 5 * 2 unique channel names and ids
+        assertThat(history.getPooledStringsToWrite().length).isEqualTo(11);
+        assertThat(history.getNotificationsToWrite())
+                .containsExactlyElementsIn(postRemoveExpectedEntries);
+    }
+
+    @Test
+    public void testParceling() {
+        NotificationHistory history = new NotificationHistory();
+
+        List<HistoricalNotification> expectedEntries = new ArrayList<>();
+        for (int i = 10; i >= 1; i--) {
+            HistoricalNotification n = getHistoricalNotification(i);
+            expectedEntries.add(n);
+            history.addNotificationToWrite(n);
+        }
+        history.poolStringsFromNotifications();
+
+        Parcel parcel = Parcel.obtain();
+        history.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        NotificationHistory parceledHistory = NotificationHistory.CREATOR.createFromParcel(parcel);
+
+        assertThat(parceledHistory.getHistoryCount()).isEqualTo(expectedEntries.size());
+
+        for (int i = 0; i < expectedEntries.size(); i++) {
+            assertThat(parceledHistory.hasNextNotification()).isTrue();
+
+            HistoricalNotification postParcelNotification = parceledHistory.getNextNotification();
+            assertThat(postParcelNotification).isEqualTo(expectedEntries.get(i));
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java
index f14f289..e140ad2 100644
--- a/core/tests/coretests/src/android/content/ContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ContentResolverTest.java
@@ -82,22 +82,23 @@
 
         final AssetFileDescriptor afd = new AssetFileDescriptor(
                 new ParcelFileDescriptor(mImage.getFileDescriptor()), 0, mSize, null);
-        when(mProvider.openTypedAssetFile(any(), any(), any(), any(), any())).thenReturn(afd);
+        when(mProvider.openTypedAssetFile(any(), any(), any(), any(), any(), any())).thenReturn(
+                afd);
     }
 
-    private static void assertImageAspectAndContents(Bitmap bitmap) {
+    private static void assertImageAspectAndContents(int width, int height, Bitmap bitmap) {
         // And correct aspect ratio
-        final int before = (100 * 1280) / 960;
+        final int before = (100 * width) / height;
         final int after = (100 * bitmap.getWidth()) / bitmap.getHeight();
         assertEquals(before, after);
 
         // And scaled correctly
         final int halfX = bitmap.getWidth() / 2;
         final int halfY = bitmap.getHeight() / 2;
-        assertEquals(Color.BLUE, bitmap.getPixel(halfX - 10, halfY - 10));
-        assertEquals(Color.RED, bitmap.getPixel(halfX + 10, halfY - 10));
-        assertEquals(Color.RED, bitmap.getPixel(halfX - 10, halfY + 10));
-        assertEquals(Color.RED, bitmap.getPixel(halfX + 10, halfY + 10));
+        assertEquals(Color.BLUE, bitmap.getPixel(halfX - 5, halfY - 5));
+        assertEquals(Color.RED, bitmap.getPixel(halfX + 5, halfY - 5));
+        assertEquals(Color.RED, bitmap.getPixel(halfX - 5, halfY + 5));
+        assertEquals(Color.RED, bitmap.getPixel(halfX + 5, halfY + 5));
     }
 
     @Test
@@ -112,7 +113,7 @@
         assertEquals(1280, res.getWidth());
         assertEquals(960, res.getHeight());
 
-        assertImageAspectAndContents(res);
+        assertImageAspectAndContents(1280, 960, res);
     }
 
     @Test
@@ -127,7 +128,7 @@
         assertTrue(res.getWidth() <= 640);
         assertTrue(res.getHeight() <= 480);
 
-        assertImageAspectAndContents(res);
+        assertImageAspectAndContents(1280, 960, res);
     }
 
     @Test
@@ -142,7 +143,7 @@
         assertTrue(res.getWidth() <= 640);
         assertTrue(res.getHeight() <= 480);
 
-        assertImageAspectAndContents(res);
+        assertImageAspectAndContents(1280, 960, res);
     }
 
     @Test
@@ -157,7 +158,23 @@
         assertEquals(32, res.getWidth());
         assertEquals(24, res.getHeight());
 
-        assertImageAspectAndContents(res);
+        assertImageAspectAndContents(32, 24, res);
+    }
+
+    @Test
+    public void testLoadThumbnail_Large() throws Exception {
+        // Test very large and extreme ratio image
+        initImage(1080, 30000);
+
+        Bitmap res = ContentResolver.loadThumbnail(mClient,
+                Uri.parse("content://com.example/"), new Size(1080, 540), null,
+                ImageDecoder.ALLOCATOR_SOFTWARE);
+
+        // Size should be much smaller
+        assertTrue(res.getWidth() <= 2160);
+        assertTrue(res.getHeight() <= 1080);
+
+        assertImageAspectAndContents(1080, 30000, res);
     }
 
     @Test
diff --git a/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java b/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
deleted file mode 100644
index f6527da..0000000
--- a/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import android.net.Uri;
-import android.os.Parcel;
-import android.test.AndroidTestCase;
-
-import androidx.test.filters.LargeTest;
-
-/**
- * Tests the android.content.pm.VerificationParams class
- *
- * To test run:
- * ./development/testrunner/runtest.py frameworks-core -c android.content.pm.VerificationParamsTest
- */
-@LargeTest
-public class VerificationParamsTest extends AndroidTestCase {
-
-    private final static String VERIFICATION_URI_STRING = "http://verification.uri/path";
-    private final static String ORIGINATING_URI_STRING = "http://originating.uri/path";
-    private final static String REFERRER_STRING = "http://referrer.uri/path";
-    private final static int INSTALLER_UID = 42;
-
-    private final static Uri VERIFICATION_URI = Uri.parse(VERIFICATION_URI_STRING);
-    private final static Uri ORIGINATING_URI = Uri.parse(ORIGINATING_URI_STRING);
-    private final static Uri REFERRER = Uri.parse(REFERRER_STRING);
-
-    private final static int ORIGINATING_UID = 10042;
-
-    public void testParcel() throws Exception {
-        VerificationParams expected = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID);
-
-        Parcel parcel = Parcel.obtain();
-        expected.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-
-        VerificationParams actual = VerificationParams.CREATOR.createFromParcel(parcel);
-
-        assertEquals(VERIFICATION_URI, actual.getVerificationURI());
-
-        assertEquals(ORIGINATING_URI, actual.getOriginatingURI());
-
-        assertEquals(REFERRER, actual.getReferrer());
-
-        assertEquals(ORIGINATING_UID, actual.getOriginatingUid());
-    }
-
-    public void testEquals_Success() throws Exception {
-        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID);
-
-        VerificationParams params2 = new VerificationParams(
-                Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
-
-        assertEquals(params1, params2);
-    }
-
-    public void testEquals_VerificationUri_Failure() throws Exception {
-        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID);
-
-        VerificationParams params2 = new VerificationParams(
-                Uri.parse("http://a.different.uri/"), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_OriginatingUri_Failure() throws Exception {
-        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID);
-
-        VerificationParams params2 = new VerificationParams(
-                Uri.parse(VERIFICATION_URI_STRING), Uri.parse("http://a.different.uri/"),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_Referrer_Failure() throws Exception {
-        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID);
-
-        VerificationParams params2 = new VerificationParams(
-                Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse("http://a.different.uri/"), ORIGINATING_UID);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_Originating_Uid_Failure() throws Exception {
-        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID);
-
-        VerificationParams params2 = new VerificationParams(
-                Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), 12345);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_InstallerUid_Failure() throws Exception {
-        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID);
-
-        VerificationParams params2 = new VerificationParams(
-                Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
-        params2.setInstallerUid(INSTALLER_UID);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testHashCode_Success() throws Exception {
-        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID);
-
-        VerificationParams params2 = new VerificationParams(
-                Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
-
-        assertEquals(params1.hashCode(), params2.hashCode());
-    }
-
-    public void testHashCode_VerificationUri_Failure() throws Exception {
-        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID);
-
-        VerificationParams params2 = new VerificationParams(null, Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_OriginatingUri_Failure() throws Exception {
-        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID);
-
-        VerificationParams params2 = new VerificationParams(
-                Uri.parse(VERIFICATION_URI_STRING), Uri.parse("http://a.different.uri/"),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_Referrer_Failure() throws Exception {
-        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID);
-
-        VerificationParams params2 = new VerificationParams(
-                Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING), null,
-                ORIGINATING_UID);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_Originating_Uid_Failure() throws Exception {
-        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID);
-
-        VerificationParams params2 = new VerificationParams(
-                Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), 12345);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_InstallerUid_Failure() throws Exception {
-        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID);
-
-        VerificationParams params2 = new VerificationParams(
-                Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
-        params2.setInstallerUid(INSTALLER_UID);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-}
diff --git a/core/tests/coretests/src/android/content/res/ConfigurationTest.java b/core/tests/coretests/src/android/content/res/ConfigurationTest.java
index 4a93f42..c231e61 100644
--- a/core/tests/coretests/src/android/content/res/ConfigurationTest.java
+++ b/core/tests/coretests/src/android/content/res/ConfigurationTest.java
@@ -16,6 +16,18 @@
 
 package android.content.res;
 
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOW_CONFIG_ROTATION;
+import static android.app.WindowConfiguration.WINDOW_CONFIG_WINDOWING_MODE;
+import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
+import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+import static android.content.pm.ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
+import static android.view.Surface.ROTATION_90;
+
 import android.content.Context;
 import android.os.LocaleList;
 import android.platform.test.annotations.Presubmit;
@@ -104,6 +116,38 @@
                 read.getLocales().indexOf(urduExtension) != -1);
     }
 
+    @Test
+    public void testMaskedSet() {
+        Configuration config = new Configuration();
+        Configuration other = new Configuration();
+        config.smallestScreenWidthDp = 100;
+        config.orientation = ORIENTATION_LANDSCAPE;
+        config.windowConfiguration.setRotation(ROTATION_90);
+        other.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        other.orientation = ORIENTATION_PORTRAIT;
+
+        // no change
+        config.setTo(other, 0, 0);
+        assertEquals(100, config.smallestScreenWidthDp);
+        assertEquals(ORIENTATION_LANDSCAPE, config.orientation);
+        assertEquals(ROTATION_90, config.windowConfiguration.getRotation());
+
+        final int justOrientationAndWindowConfig = CONFIG_ORIENTATION | CONFIG_WINDOW_CONFIGURATION;
+        config.setTo(other, justOrientationAndWindowConfig, WINDOW_CONFIG_WINDOWING_MODE);
+        assertEquals(100, config.smallestScreenWidthDp);
+        assertEquals(other.orientation, config.orientation);
+        assertEquals(other.windowConfiguration.getWindowingMode(),
+                config.windowConfiguration.getWindowingMode());
+        assertEquals(ROTATION_90, config.windowConfiguration.getRotation());
+
+        // unset
+        final int justSmallestSwAndWindowConfig =
+                CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_WINDOW_CONFIGURATION;
+        config.setTo(other, justSmallestSwAndWindowConfig, WINDOW_CONFIG_ROTATION);
+        assertEquals(ROTATION_UNDEFINED, config.windowConfiguration.getRotation());
+        assertEquals(SMALLEST_SCREEN_WIDTH_DP_UNDEFINED, config.smallestScreenWidthDp);
+    }
+
     private void writeToProto(File f, Configuration config) throws Exception {
         final AtomicFile af = new AtomicFile(f);
         FileOutputStream fos = af.startWrite();
diff --git a/core/tests/coretests/src/android/graphics/TypefaceEqualsTest.java b/core/tests/coretests/src/android/graphics/TypefaceEqualsTest.java
new file mode 100644
index 0000000..6ae7eb7
--- /dev/null
+++ b/core/tests/coretests/src/android/graphics/TypefaceEqualsTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 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.graphics;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.content.res.AssetManager;
+import android.graphics.fonts.Font;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.IOException;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TypefaceEqualsTest {
+    @Test
+    public void testFontEqualWithLocale() throws IOException {
+        final AssetManager am =
+                InstrumentationRegistry.getInstrumentation().getContext().getAssets();
+
+        Font masterFont = new Font.Builder(am, "fonts/a3em.ttf").build();
+
+        Font jaFont = new Font.Builder(masterFont.getBuffer(), new File("fonts/a3em.ttf"), "ja")
+                .build();
+        Font jaFont2 = new Font.Builder(masterFont.getBuffer(), new File("fonts/a3em.ttf"), "ja")
+                .build();
+        Font koFont = new Font.Builder(masterFont.getBuffer(), new File("fonts/a3em.ttf"), "ko")
+                .build();
+
+        assertEquals(jaFont, jaFont2);
+        assertNotEquals(jaFont, koFont);
+        assertNotEquals(jaFont, masterFont);
+    }
+}
diff --git a/core/tests/coretests/src/android/provider/DeviceConfigTest.java b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
index 77b7f2a..0c83390 100644
--- a/core/tests/coretests/src/android/provider/DeviceConfigTest.java
+++ b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
@@ -16,12 +16,10 @@
 
 package android.provider;
 
-import static android.provider.DeviceConfig.OnPropertiesChangedListener;
 import static android.provider.DeviceConfig.Properties;
 
 import static com.google.common.truth.Truth.assertThat;
 
-import android.app.ActivityThread;
 import android.content.ContentResolver;
 import android.os.Bundle;
 import android.platform.test.annotations.Presubmit;
@@ -35,9 +33,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
 /** Tests that ensure appropriate settings are backed up. */
 @Presubmit
 @RunWith(AndroidJUnit4.class)
@@ -393,6 +388,13 @@
         assertThat(properties.getKeyset()).containsExactly(KEY, KEY2);
         assertThat(properties.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE3);
         assertThat(properties.getString(KEY2, DEFAULT_VALUE)).isEqualTo(VALUE2);
+
+        DeviceConfig.setProperty(NAMESPACE, KEY3, VALUE, false);
+        properties = DeviceConfig.getProperties(NAMESPACE);
+        assertThat(properties.getKeyset()).containsExactly(KEY, KEY2, KEY3);
+        assertThat(properties.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE3);
+        assertThat(properties.getString(KEY2, DEFAULT_VALUE)).isEqualTo(VALUE2);
+        assertThat(properties.getString(KEY3, DEFAULT_VALUE)).isEqualTo(VALUE);
     }
 
     @Test
@@ -482,29 +484,30 @@
         assertThat(properties.getString(KEY3, DEFAULT_VALUE)).isEqualTo(DEFAULT_VALUE);
     }
 
-    @Test
-    public void testOnPropertiesChangedListener() throws InterruptedException {
-        final CountDownLatch countDownLatch = new CountDownLatch(1);
-
-        OnPropertiesChangedListener changeListener = (properties) -> {
-            assertThat(properties.getNamespace()).isEqualTo(NAMESPACE);
-            assertThat(properties.getKeyset()).contains(KEY);
-            assertThat(properties.getString(KEY, "default_value")).isEqualTo(VALUE);
-            countDownLatch.countDown();
-        };
-
-        try {
-            DeviceConfig.addOnPropertiesChangedListener(NAMESPACE,
-                    ActivityThread.currentApplication().getMainExecutor(), changeListener);
-            DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false);
-            assertThat(countDownLatch.await(
-                    WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
-        } catch (InterruptedException e) {
-            Assert.fail(e.getMessage());
-        } finally {
-            DeviceConfig.removeOnPropertiesChangedListener(changeListener);
-        }
-    }
+    // TODO(mpape): resolve b/142727848 and re-enable this test
+//    @Test
+//    public void testOnPropertiesChangedListener() throws InterruptedException {
+//        final CountDownLatch countDownLatch = new CountDownLatch(1);
+//
+//        OnPropertiesChangedListener changeListener = (properties) -> {
+//            assertThat(properties.getNamespace()).isEqualTo(NAMESPACE);
+//            assertThat(properties.getKeyset()).contains(KEY);
+//            assertThat(properties.getString(KEY, "default_value")).isEqualTo(VALUE);
+//            countDownLatch.countDown();
+//        };
+//
+//        try {
+//            DeviceConfig.addOnPropertiesChangedListener(NAMESPACE,
+//                    ActivityThread.currentApplication().getMainExecutor(), changeListener);
+//            DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false);
+//            assertThat(countDownLatch.await(
+//                    WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
+//        } catch (InterruptedException e) {
+//            Assert.fail(e.getMessage());
+//        } finally {
+//            DeviceConfig.removeOnPropertiesChangedListener(changeListener);
+//        }
+//    }
 
     private static boolean deleteViaContentProvider(String namespace, String key) {
         ContentResolver resolver = InstrumentationRegistry.getContext().getContentResolver();
diff --git a/core/tests/coretests/src/android/provider/TestDocumentsProvider.java b/core/tests/coretests/src/android/provider/TestDocumentsProvider.java
index 1bd8ff6..5f640be 100644
--- a/core/tests/coretests/src/android/provider/TestDocumentsProvider.java
+++ b/core/tests/coretests/src/android/provider/TestDocumentsProvider.java
@@ -93,12 +93,14 @@
     }
 
     @Override
-    protected int enforceReadPermissionInner(Uri uri, String callingPkg, IBinder callerToken) {
+    protected int enforceReadPermissionInner(Uri uri, String callingPkg,
+            @Nullable String callingFeatureId, IBinder callerToken) {
         return AppOpsManager.MODE_ALLOWED;
     }
 
     @Override
-    protected int enforceWritePermissionInner(Uri uri, String callingPkg, IBinder callerToken) {
+    protected int enforceWritePermissionInner(Uri uri, String callingPkg,
+            @Nullable String callingFeatureId, IBinder callerToken) {
         return AppOpsManager.MODE_ALLOWED;
     }
 
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 5ea91da..d427cbd 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -24,12 +24,12 @@
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
-import static com.android.internal.app.ChooserActivity.CALLER_TARGET_SCORE_BOOST;
-import static com.android.internal.app.ChooserActivity.SHORTCUT_TARGET_SCORE_BOOST;
 import static com.android.internal.app.ChooserActivity.TARGET_TYPE_CHOOSER_TARGET;
 import static com.android.internal.app.ChooserActivity.TARGET_TYPE_DEFAULT;
 import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE;
 import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER;
+import static com.android.internal.app.ChooserListAdapter.CALLER_TARGET_SCORE_BOOST;
+import static com.android.internal.app.ChooserListAdapter.SHORTCUT_TARGET_SCORE_BOOST;
 import static com.android.internal.app.ChooserWrapperActivity.sOverrides;
 
 import static org.hamcrest.CoreMatchers.is;
@@ -69,6 +69,7 @@
 
 import com.android.internal.R;
 import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
+import com.android.internal.app.chooser.DisplayResolveInfo;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
@@ -819,17 +820,18 @@
         when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
                 Mockito.anyBoolean(),
                 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
-        when(sOverrides.resolverListController.getScore(Mockito.isA(
-                ResolverActivity.DisplayResolveInfo.class))).thenReturn(testBaseScore);
+        when(sOverrides.resolverListController.getScore(Mockito.isA(DisplayResolveInfo.class)))
+                .thenReturn(testBaseScore);
 
         final ChooserWrapperActivity activity = mActivityRule
                 .launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
 
-        final ResolverActivity.DisplayResolveInfo testDri =
+        final DisplayResolveInfo testDri =
                 activity.createTestDisplayResolveInfo(sendIntent,
-                ResolverDataProvider.createResolveInfo(3, 0), "testLabel", "testInfo", sendIntent);
-        final ChooserActivity.ChooserListAdapter adapter = activity.getAdapter();
+                ResolverDataProvider.createResolveInfo(3, 0), "testLabel", "testInfo", sendIntent,
+                /* resolveInfoPresentationGetter */ null);
+        final ChooserListAdapter adapter = activity.getAdapter();
 
         assertThat(adapter.getBaseScore(null, 0), is(CALLER_TARGET_SCORE_BOOST));
         assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_DEFAULT), is(testBaseScore));
@@ -970,7 +972,8 @@
                                 ri,
                                 "testLabel",
                                 "testInfo",
-                                sendIntent),
+                                sendIntent,
+                                /* resolveInfoPresentationGetter */ null),
                         serviceTargets,
                         TARGET_TYPE_CHOOSER_TARGET)
         );
@@ -1036,7 +1039,8 @@
                                 ri,
                                 "testLabel",
                                 "testInfo",
-                                sendIntent),
+                                sendIntent,
+                                /* resolveInfoPresentationGetter */ null),
                         serviceTargets,
                         TARGET_TYPE_CHOOSER_TARGET)
         );
@@ -1097,7 +1101,8 @@
                                 ri,
                                 "testLabel",
                                 "testInfo",
-                                sendIntent),
+                                sendIntent,
+                                /* resolveInfoPresentationGetter */ null),
                         serviceTargets,
                         TARGET_TYPE_CHOOSER_TARGET)
         );
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index 1d567c7..03705d0 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -18,6 +18,7 @@
 
 import static org.mockito.Mockito.mock;
 
+import android.annotation.Nullable;
 import android.app.usage.UsageStatsManager;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -30,6 +31,9 @@
 import android.net.Uri;
 import android.util.Size;
 
+import com.android.internal.app.ResolverListAdapter.ResolveInfoPresentationGetter;
+import com.android.internal.app.chooser.DisplayResolveInfo;
+import com.android.internal.app.chooser.TargetInfo;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
@@ -64,7 +68,7 @@
     }
 
     @Override
-    public void safelyStartActivity(TargetInfo cti) {
+    public void safelyStartActivity(com.android.internal.app.chooser.TargetInfo cti) {
         if (sOverrides.onSafelyStartCallback != null &&
                 sOverrides.onSafelyStartCallback.apply(cti)) {
             return;
@@ -133,8 +137,10 @@
     }
 
     public DisplayResolveInfo createTestDisplayResolveInfo(Intent originalIntent, ResolveInfo pri,
-            CharSequence pLabel, CharSequence pInfo, Intent pOrigIntent) {
-        return new DisplayResolveInfo(originalIntent, pri, pLabel, pInfo, pOrigIntent);
+            CharSequence pLabel, CharSequence pInfo, Intent replacementIntent,
+            @Nullable ResolveInfoPresentationGetter resolveInfoPresentationGetter) {
+        return new DisplayResolveInfo(originalIntent, pri, pLabel, pInfo, replacementIntent,
+                resolveInfoPresentationGetter);
     }
 
     /**
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index 453bddd..a401e21 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -38,14 +38,15 @@
 import android.widget.RelativeLayout;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.espresso.Espresso;
 import androidx.test.rule.ActivityTestRule;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.R;
-import com.android.internal.app.ResolverActivity.ActivityInfoPresentationGetter;
-import com.android.internal.app.ResolverActivity.ResolveInfoPresentationGetter;
 import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
 import com.android.internal.app.ResolverDataProvider.PackageManagerMockedInfo;
+import com.android.internal.app.ResolverListAdapter.ActivityInfoPresentationGetter;
+import com.android.internal.app.ResolverListAdapter.ResolveInfoPresentationGetter;
 import com.android.internal.widget.ResolverDrawerLayout;
 
 import org.junit.Before;
@@ -82,6 +83,7 @@
                 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
 
         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
+        Espresso.registerIdlingResources(activity.getAdapter().getLabelIdlingResource());
         waitForIdle();
 
         assertThat(activity.getAdapter().getCount(), is(2));
@@ -214,6 +216,7 @@
                 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
 
         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
+        Espresso.registerIdlingResources(activity.getAdapter().getLabelIdlingResource());
         waitForIdle();
 
         // The other entry is filtered to the last used slot
@@ -251,6 +254,7 @@
                 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
 
         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
+        Espresso.registerIdlingResources(activity.getAdapter().getLabelIdlingResource());
         waitForIdle();
 
         // The other entry is filtered to the other profile slot
@@ -296,6 +300,7 @@
                 .thenReturn(resolvedComponentInfos.get(1).getResolveInfoAt(0));
 
         final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
+        Espresso.registerIdlingResources(activity.getAdapter().getLabelIdlingResource());
         waitForIdle();
 
         // The other entry is filtered to the other profile slot
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java
index 6218fa9..5ac1489 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverListControllerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.app;
 
+import static junit.framework.Assert.assertEquals;
+
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.mockito.Matchers.any;
@@ -126,7 +128,7 @@
         String annotation = "test_annotation";
         Intent sendIntent = createSendImageIntent(annotation);
         String refererPackage = "test_referer_package";
-        List<ResolvedComponentInfo> resolvedComponents = createResolvedComponentsForTest(15);
+        List<ResolvedComponentInfo> resolvedComponents = createResolvedComponentsForTest(10);
         mUsm = new UsageStatsManager(mMockContext, mMockService);
         when(mMockContext.getSystemService(Context.USAGE_STATS_SERVICE)).thenReturn(mUsm);
         mController = new ResolverListController(mMockContext, mMockPackageManager, sendIntent,
@@ -135,7 +137,18 @@
         mController.topK(topKList, 5);
         List<ResolvedComponentInfo> sortList = new ArrayList<>(topKList);
         mController.sort(sortList);
-        assertThat(sortList.subList(0, 5), is(topKList.subList(0, 5)));
+        assertEquals("Top k elements should be sorted when input size greater than k.",
+                sortList.subList(0, 5), topKList.subList(0, 5));
+        mController.topK(topKList, 10);
+        sortList = new ArrayList<>(topKList);
+        mController.sort(sortList);
+        assertEquals("All elements should be sorted when input size equals k.",
+                sortList, topKList);
+        mController.topK(topKList, 15);
+        sortList = new ArrayList<>(topKList);
+        mController.sort(sortList);
+        assertEquals("All elements should be sorted when input size less than k.",
+                sortList, topKList);
     }
 
     private UsageStats initStats(String packageName, String action,
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
index 83f6bc2..39cc83c 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
@@ -19,8 +19,14 @@
 import static org.mockito.Mockito.mock;
 
 import android.app.usage.UsageStatsManager;
+import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 
+import com.android.internal.app.chooser.TargetInfo;
+
+import java.util.List;
 import java.util.function.Function;
 
 /*
@@ -30,8 +36,16 @@
     static final OverrideData sOverrides = new OverrideData();
     private UsageStatsManager mUsm;
 
-    ResolveListAdapter getAdapter() {
-        return mAdapter;
+    @Override
+    public ResolverListAdapter createAdapter(Context context, List<Intent> payloadIntents,
+            Intent[] initialIntents, List<ResolveInfo> rList, boolean filterLastUsed,
+            boolean useLayoutForBrowsables) {
+        return new ResolverWrapperAdapter(context, payloadIntents, initialIntents, rList,
+                filterLastUsed, createListController(), useLayoutForBrowsables, this);
+    }
+
+    ResolverWrapperAdapter getAdapter() {
+        return (ResolverWrapperAdapter) mAdapter;
     }
 
     @Override
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperAdapter.java b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperAdapter.java
new file mode 100644
index 0000000..a2191b5
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperAdapter.java
@@ -0,0 +1,71 @@
+/*
+ * 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.internal.app;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+
+import androidx.test.espresso.idling.CountingIdlingResource;
+
+import com.android.internal.app.chooser.DisplayResolveInfo;
+
+import java.util.List;
+
+public class ResolverWrapperAdapter extends ResolverListAdapter {
+
+    private CountingIdlingResource mLabelIdlingResource =
+            new CountingIdlingResource("LoadLabelTask");
+
+    public ResolverWrapperAdapter(Context context,
+            List<Intent> payloadIntents,
+            Intent[] initialIntents,
+            List<ResolveInfo> rList, boolean filterLastUsed,
+            ResolverListController resolverListController, boolean useLayoutForBrowsables,
+            ResolverListCommunicator resolverListCommunicator) {
+        super(context, payloadIntents, initialIntents, rList, filterLastUsed,
+                resolverListController,
+                useLayoutForBrowsables, resolverListCommunicator, false);
+    }
+
+    public CountingIdlingResource getLabelIdlingResource() {
+        return mLabelIdlingResource;
+    }
+
+    @Override
+    protected LoadLabelTask getLoadLabelTask(DisplayResolveInfo info, ViewHolder holder) {
+        return new LoadLabelWrapperTask(info, holder);
+    }
+
+    class LoadLabelWrapperTask extends LoadLabelTask {
+
+        protected LoadLabelWrapperTask(DisplayResolveInfo dri, ViewHolder holder) {
+            super(dri, holder);
+        }
+
+        @Override
+        protected void onPreExecute() {
+            mLabelIdlingResource.increment();
+        }
+
+        @Override
+        protected void onPostExecute(CharSequence[] result) {
+            super.onPostExecute(result);
+            mLabelIdlingResource.decrement();
+        }
+    }
+}
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index b3f6fdb..364e4ea 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -46,10 +46,12 @@
 import android.os.Binder;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
 import android.view.WindowManagerGlobal;
 
 import androidx.test.annotation.UiThreadTest;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.MediumTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
@@ -70,6 +72,8 @@
  */
 @RunWith(AndroidJUnit4.class)
 @MediumTest
+@Presubmit
+@FlakyTest(bugId = 143153552)
 public class ActivityThreadClientTest {
 
     @Test
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index dceb243..80098c5 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -174,6 +174,7 @@
     <assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="incidentd" />
     <assign-permission name="android.permission.INTERACT_ACROSS_USERS" uid="incidentd" />
     <assign-permission name="android.permission.REQUEST_INCIDENT_REPORT_APPROVAL" uid="incidentd" />
+    <assign-permission name="android.permission.PEEK_DROPBOX_DATA" uid="incidentd" />
 
     <assign-permission name="android.permission.ACCESS_LOWPAN_STATE" uid="lowpan" />
     <assign-permission name="android.permission.MANAGE_LOWPAN_INTERFACES" uid="lowpan" />
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index ac742e2..a0215e1 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -370,6 +370,7 @@
         <permission name="android.permission.LOCAL_MAC_ADDRESS"/>
         <permission name="android.permission.MANAGE_USERS"/>
         <permission name="android.permission.PACKAGE_USAGE_STATS"/>
+        <permission name="android.permission.READ_DEVICE_CONFIG"/>
         <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
         <permission name="android.permission.REQUEST_NETWORK_SCORES"/>
         <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 012ffcc..1326952 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -169,12 +169,6 @@
       "group": "WM_DEBUG_RESIZE",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
-    "-1822611824": {
-      "message": "\tRemove token=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
     "-1797409732": {
       "message": "Skipping %s because %s",
       "level": "VERBOSE",
@@ -421,6 +415,12 @@
       "group": "WM_SHOW_TRANSACTIONS",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-1248645819": {
+      "message": "\tAdd container=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
     "-1219773477": {
       "message": "setInputConsumerEnabled(%s): mCanceled=%b",
       "level": "DEBUG",
@@ -493,12 +493,6 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/RootWindowContainer.java"
     },
-    "-1099052739": {
-      "message": "\tAdd token=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
     "-1089874824": {
       "message": "SURFACE SHOW (performLayout): %s",
       "level": "INFO",
@@ -721,6 +715,12 @@
       "group": "WM_DEBUG_SCREEN_ON",
       "at": "com\/android\/server\/wm\/DisplayContent.java"
     },
+    "-633961578": {
+      "message": "applyAnimation: transition animation is disabled or skipped. container=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
     "-622997754": {
       "message": "postWindowRemoveCleanupLocked: %s",
       "level": "VERBOSE",
@@ -817,12 +817,6 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/DisplayRotation.java"
     },
-    "-415912575": {
-      "message": "setTask: %s at top.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
     "-415865166": {
       "message": "findFocusedWindow: Found new focus @ %s",
       "level": "VERBOSE",
@@ -883,10 +877,10 @@
       "group": "WM_DEBUG_ADD_REMOVE",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
-    "-253016819": {
-      "message": "applyAnimation: transition animation is disabled or skipped. atoken=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+    "-303497363": {
+      "message": "reparent: moving activity=%s to task=%d at %d",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
     "-251259736": {
@@ -919,12 +913,6 @@
       "group": "WM_DEBUG_APP_TRANSITIONS",
       "at": "com\/android\/server\/wm\/AppTransitionController.java"
     },
-    "-121104356": {
-      "message": "Remove %s: mSurfaceController=%s mAnimatingExit=%b mRemoveOnExit=%b mHasSurface=%b surfaceShowing=%b animating=%b app-animation=%b mWillReplaceWindow=%b inPendingTransaction=%b mDisplayFrozen=%b callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
     "-116086365": {
       "message": "******************** ENABLING SCREEN!",
       "level": "INFO",
@@ -961,6 +949,12 @@
       "group": "WM_SHOW_TRANSACTIONS",
       "at": "com\/android\/server\/wm\/Session.java"
     },
+    "-33096143": {
+      "message": "applyAnimation: transition animation is disabled or skipped. container=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
     "-29233992": {
       "message": "SURFACE CLEAR CROP: %s",
       "level": "INFO",
@@ -1237,12 +1231,6 @@
       "group": "WM_DEBUG_FOCUS_LIGHT",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "393054329": {
-      "message": "reParentWindowToken: removing window token=%s from task=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
     "399841913": {
       "message": "SURFACE RECOVER DESTROY: %s",
       "level": "INFO",
@@ -1339,6 +1327,12 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
+    "594260654": {
+      "message": "Remove %s: mSurfaceController=%s mAnimatingExit=%b mRemoveOnExit=%b mHasSurface=%b surfaceShowing=%b animating=%b app-animation=%b mWillReplaceWindow=%b mDisplayFrozen=%b callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
     "600140673": {
       "message": "checkBootAnimationComplete: Waiting for anim complete",
       "level": "INFO",
@@ -1351,6 +1345,12 @@
       "group": "WM_SHOW_TRANSACTIONS",
       "at": "com\/android\/server\/wm\/Session.java"
     },
+    "609651209": {
+      "message": "addChild: %s at top.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/TaskRecord.java"
+    },
     "620368427": {
       "message": "******* TELLING SURFACE FLINGER WE ARE BOOTED!",
       "level": "INFO",
@@ -1375,6 +1375,12 @@
       "group": "WM_SHOW_TRANSACTIONS",
       "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
     },
+    "638429464": {
+      "message": "\tRemove container=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
     "644675193": {
       "message": "Real start recents",
       "level": "DEBUG",
@@ -1465,12 +1471,6 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "815803557": {
-      "message": "applyAnimation: atoken=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
     "829434921": {
       "message": "Draw state now committed in %s",
       "level": "VERBOSE",
@@ -1543,6 +1543,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "972354148": {
+      "message": "\tcontainer=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
     "1001904964": {
       "message": "***** BOOT TIMEOUT: forcing display enabled",
       "level": "WARN",
@@ -1675,12 +1681,6 @@
       "group": "WM_DEBUG_FOCUS",
       "at": "com\/android\/server\/wm\/DisplayContent.java"
     },
-    "1358786604": {
-      "message": "No thumbnail header bitmap for: %d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
     "1364498663": {
       "message": "notifyAppResumed: wasStopped=%b %s",
       "level": "VERBOSE",
@@ -1795,11 +1795,11 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
     },
-    "1531527061": {
-      "message": "createAnimationAdapter(): token=%s",
+    "1528528509": {
+      "message": "No thumbnail header bitmap for: %s",
       "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
     "1563755163": {
       "message": "Permission Denial: %s from pid=%d, uid=%d requires %s",
@@ -1819,6 +1819,12 @@
       "group": "WM_DEBUG_ADD_REMOVE",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
+    "1584270979": {
+      "message": "applyAnimation: container=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
     "1589610525": {
       "message": "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: anim=%s transit=%s isEntrance=true Callers=%s",
       "level": "VERBOSE",
@@ -1909,11 +1915,11 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "1804869745": {
+    "1831008694": {
       "message": "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s surfaceInsets=%s",
       "level": "DEBUG",
       "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
     },
     "1836214582": {
       "message": "startingData was nulled out before handling mAddStartingWindow: %s",
@@ -1939,12 +1945,6 @@
       "group": "WM_DEBUG_SCREEN_ON",
       "at": "com\/android\/server\/wm\/DisplayPolicy.java"
     },
-    "1865246212": {
-      "message": "\tapp=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
     "1866772666": {
       "message": "SAFE MODE not enabled",
       "level": "INFO",
@@ -1999,12 +1999,6 @@
       "group": "WM_SHOW_TRANSACTIONS",
       "at": "com\/android\/server\/wm\/WindowAnimator.java"
     },
-    "1995048598": {
-      "message": "reparent: moving app token=%s to task=%d at %d",
-      "level": "INFO",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
     "2016061474": {
       "message": "Prepare app transition: transit=%s %s alwaysKeepCurrent=%b displayId=%d Callers=%s",
       "level": "VERBOSE",
@@ -2023,6 +2017,12 @@
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "2022422429": {
+      "message": "createAnimationAdapter(): container=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
     "2028163120": {
       "message": "applyAnimation: anim=%s nextAppTransition=ANIM_SCALE_UP transit=%s isEntrance=%s Callers=%s",
       "level": "VERBOSE",
diff --git a/data/keyboards/Vendor_1532_Product_0900.kl b/data/keyboards/Vendor_1532_Product_0900.kl
index c2fc1b4..4c6c4dd 100644
--- a/data/keyboards/Vendor_1532_Product_0900.kl
+++ b/data/keyboards/Vendor_1532_Product_0900.kl
@@ -20,13 +20,19 @@
 key 308 BUTTON_Y
 key 310 BUTTON_L1
 key 311 BUTTON_R1
-key 316 BUTTON_MODE
 key 317 BUTTON_THUMBL
 key 318 BUTTON_THUMBR
 
 key 158 BACK
 key 172 HOME
 
+# Left arrow to the left of the "power" key
+key 0x13a BUTTON_SELECT
+# Right arrow to the right of the "power" key
+key 0x13b BUTTON_START
+# Power key
+key 0x13c BUTTON_MODE
+
 axis 0x00 X
 axis 0x01 Y
 axis 0x02 Z
diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java
index 64fc704..6c90c4c 100644
--- a/graphics/java/android/graphics/drawable/DrawableWrapper.java
+++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java
@@ -364,6 +364,13 @@
     }
 
     @Override
+    public void jumpToCurrentState() {
+        if (mDrawable != null) {
+            mDrawable.jumpToCurrentState();
+        }
+    }
+
+    @Override
     protected boolean onLevelChange(int level) {
         return mDrawable != null && mDrawable.setLevel(level);
     }
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index c6586ec..45b2de5 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -784,7 +784,9 @@
             mFillPaint.setDither(st.mDither);
             mFillPaint.setColorFilter(colorFilter);
             if (colorFilter != null && st.mSolidColors == null) {
-                mFillPaint.setColor(mAlpha << 24);
+                // If we don't have a solid color and we don't have a gradient,
+                // the app is stroking the shape, set the color to transparent
+                mFillPaint.setColor(st.mGradientColors != null ? mAlpha << 24 : 0);
             }
             if (haveStroke) {
                 mStrokePaint.setAlpha(currStrokeAlpha);
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index 552088f..ba96a06 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -519,12 +519,13 @@
         }
         Font f = (Font) o;
         return mFontStyle.equals(f.mFontStyle) && f.mTtcIndex == mTtcIndex
-                && Arrays.equals(f.mAxes, mAxes) && f.mBuffer.equals(mBuffer);
+                && Arrays.equals(f.mAxes, mAxes) && f.mBuffer.equals(mBuffer)
+                && Objects.equals(f.mLocaleList, mLocaleList);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mFontStyle, mTtcIndex, Arrays.hashCode(mAxes), mBuffer);
+        return Objects.hash(mFontStyle, mTtcIndex, Arrays.hashCode(mAxes), mBuffer, mLocaleList);
     }
 
     @Override
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 54995ac..f25910b 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -71,6 +71,15 @@
     /** Key containing suffix of lockdown VPN profile. */
     public static final String LOCKDOWN_VPN = "LOCKDOWN_VPN";
 
+    /** Name of CA certificate usage. */
+    public static final String CERTIFICATE_USAGE_CA = "ca";
+
+    /** Name of User certificate usage. */
+    public static final String CERTIFICATE_USAGE_USER = "user";
+
+    /** Name of WIFI certificate usage. */
+    public static final String CERTIFICATE_USAGE_WIFI = "wifi";
+
     /** Data type for public keys. */
     public static final String EXTRA_PUBLIC_KEY = "KEY";
 
@@ -91,6 +100,11 @@
     public static final String EXTRA_INSTALL_AS_UID = "install_as_uid";
 
     /**
+     * Intent extra: type of the certificate to install
+     */
+    public static final String EXTRA_CERTIFICATE_USAGE = "certificate_install_usage";
+
+    /**
      * Intent extra: name for the user's key pair.
      */
     public static final String EXTRA_USER_KEY_ALIAS = "user_key_pair_name";
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 254456c..538319c 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -763,28 +763,33 @@
      * @see KeyChain#bind
      */
     public static class KeyChainConnection implements Closeable {
-        private final Context context;
-        private final ServiceConnection serviceConnection;
-        private final IKeyChainService service;
+        private final Context mContext;
+        private final ServiceConnection mServiceConnection;
+        private final IKeyChainService mService;
         protected KeyChainConnection(Context context,
                                      ServiceConnection serviceConnection,
                                      IKeyChainService service) {
-            this.context = context;
-            this.serviceConnection = serviceConnection;
-            this.service = service;
+            this.mContext = context;
+            this.mServiceConnection = serviceConnection;
+            this.mService = service;
         }
         @Override public void close() {
-            context.unbindService(serviceConnection);
+            mContext.unbindService(mServiceConnection);
         }
+
+        /** returns the service binder. */
         public IKeyChainService getService() {
-            return service;
+            return mService;
         }
     }
 
     /**
-     * @hide for reuse by CertInstaller and Settings.
-     *
+     * Bind to KeyChainService in the current user.
      * Caller should call unbindService on the result when finished.
+     *
+     *@throws InterruptedException if interrupted during binding.
+     *@throws AssertionError if unable to bind to KeyChainService.
+     * @hide for reuse by CertInstaller and Settings.
      */
     @WorkerThread
     public static KeyChainConnection bind(@NonNull Context context) throws InterruptedException {
@@ -792,6 +797,11 @@
     }
 
     /**
+     * Bind to KeyChainService in the target user.
+     * Caller should call unbindService on the result when finished.
+     *
+     * @throws InterruptedException if interrupted during binding.
+     * @throws AssertionError if unable to bind to KeyChainService.
      * @hide
      */
     @WorkerThread
@@ -814,6 +824,16 @@
                     }
                 }
             }
+            @Override public void onBindingDied(ComponentName name) {
+                if (!mConnectedAtLeastOnce) {
+                    mConnectedAtLeastOnce = true;
+                    try {
+                        q.put(null);
+                    } catch (InterruptedException e) {
+                        // will never happen, since the queue starts with one available slot
+                    }
+                }
+            }
             @Override public void onServiceDisconnected(ComponentName name) {}
         };
         Intent intent = new Intent(IKeyChainService.class.getName());
@@ -823,7 +843,13 @@
                 intent, keyChainServiceConnection, Context.BIND_AUTO_CREATE, user)) {
             throw new AssertionError("could not bind to KeyChainService");
         }
-        return new KeyChainConnection(context, keyChainServiceConnection, q.take());
+        IKeyChainService service = q.take();
+        if (service != null) {
+            return new KeyChainConnection(context, keyChainServiceConnection, service);
+        } else {
+            context.unbindService(keyChainServiceConnection);
+            throw new AssertionError("KeyChainService died while binding");
+        }
     }
 
     private static void ensureNotOnMainThread(@NonNull Context context) {
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 61b72cf..2041e7a 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -221,7 +221,6 @@
                 "pipeline/skia/SkiaPipeline.cpp",
                 "pipeline/skia/SkiaProfileRenderer.cpp",
                 "pipeline/skia/SkiaVulkanPipeline.cpp",
-                "pipeline/skia/VectorDrawableAtlas.cpp",
                 "pipeline/skia/VkFunctorDrawable.cpp",
                 "pipeline/skia/VkInteropFunctorDrawable.cpp",
                 "renderstate/RenderState.cpp",
@@ -347,7 +346,6 @@
         "tests/unit/ThreadBaseTests.cpp",
         "tests/unit/TypefaceTests.cpp",
         "tests/unit/VectorDrawableTests.cpp",
-        "tests/unit/VectorDrawableAtlasTests.cpp",
         "tests/unit/WebViewFunctorManagerTests.cpp",
     ],
 }
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index 40bff88..3681c69 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -302,6 +302,7 @@
     switch (skBitmap.info().colorType()) {
         case kRGBA_8888_SkColorType:
             formatInfo.isSupported = true;
+            [[fallthrough]];
         // ARGB_4444 is upconverted to RGBA_8888
         case kARGB_4444_SkColorType:
             formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index ec83a19..1eb089d 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -136,7 +136,6 @@
                                const Paint* paint) override;
     virtual double drawAnimatedImage(AnimatedImageDrawable* imgDrawable) override;
 
-    virtual bool drawTextAbsolutePos() const override { return true; }
     virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
 
     virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
diff --git a/libs/hwui/TreeInfo.cpp b/libs/hwui/TreeInfo.cpp
index dc53dd6..750f869 100644
--- a/libs/hwui/TreeInfo.cpp
+++ b/libs/hwui/TreeInfo.cpp
@@ -24,7 +24,6 @@
         : mode(mode)
         , prepareTextures(mode == MODE_FULL)
         , canvasContext(canvasContext)
-        , damageGenerationId(canvasContext.getFrameNumber())
         , disableForceDark(canvasContext.useForceDark() ? 0 : 1)
         , screenSize(canvasContext.getNextFrameSize()) {}
 
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 61403aa..217b0c4 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -496,87 +496,6 @@
     return *mCache.bitmap;
 }
 
-void Tree::updateCache(sp<skiapipeline::VectorDrawableAtlas>& atlas, GrContext* context) {
-#ifdef __ANDROID__  // Layoutlib does not support hardware acceleration
-    SkRect dst;
-    sk_sp<SkSurface> surface = mCache.getSurface(&dst);
-    bool canReuseSurface = surface && dst.width() >= mProperties.getScaledWidth() &&
-                           dst.height() >= mProperties.getScaledHeight();
-    if (!canReuseSurface) {
-        int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth());
-        int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
-        auto atlasEntry = atlas->requestNewEntry(scaledWidth, scaledHeight, context);
-        if (INVALID_ATLAS_KEY != atlasEntry.key) {
-            dst = atlasEntry.rect;
-            surface = atlasEntry.surface;
-            mCache.setAtlas(atlas, atlasEntry.key);
-        } else {
-            // don't draw, if we failed to allocate an offscreen buffer
-            mCache.clear();
-            surface.reset();
-        }
-    }
-    if (!canReuseSurface || mCache.dirty) {
-        if (surface) {
-            Bitmap& bitmap = getBitmapUpdateIfDirty();
-            SkBitmap skiaBitmap;
-            bitmap.getSkBitmap(&skiaBitmap);
-            surface->writePixels(skiaBitmap, dst.fLeft, dst.fTop);
-        }
-        mCache.dirty = false;
-    }
-#endif
-}
-
-void Tree::Cache::setAtlas(sp<skiapipeline::VectorDrawableAtlas> newAtlas,
-                           skiapipeline::AtlasKey newAtlasKey) {
-    LOG_ALWAYS_FATAL_IF(newAtlasKey == INVALID_ATLAS_KEY);
-    clear();
-    mAtlas = newAtlas;
-    mAtlasKey = newAtlasKey;
-}
-
-sk_sp<SkSurface> Tree::Cache::getSurface(SkRect* bounds) {
-    sk_sp<SkSurface> surface;
-#ifdef __ANDROID__  // Layoutlib does not support hardware acceleration
-    sp<skiapipeline::VectorDrawableAtlas> atlas = mAtlas.promote();
-    if (atlas.get() && mAtlasKey != INVALID_ATLAS_KEY) {
-        auto atlasEntry = atlas->getEntry(mAtlasKey);
-        *bounds = atlasEntry.rect;
-        surface = atlasEntry.surface;
-        mAtlasKey = atlasEntry.key;
-    }
-#endif
-
-    return surface;
-}
-
-void Tree::Cache::clear() {
-#ifdef __ANDROID__  // Layoutlib does not support hardware acceleration
-    if (mAtlasKey != INVALID_ATLAS_KEY) {
-        if (renderthread::RenderThread::isCurrent()) {
-            sp<skiapipeline::VectorDrawableAtlas> lockAtlas = mAtlas.promote();
-            if (lockAtlas.get()) {
-                lockAtlas->releaseEntry(mAtlasKey);
-            }
-        } else {
-            // VectorDrawableAtlas can be accessed only on RenderThread.
-            // Use by-copy capture of the current Cache variables, because "this" may not be valid
-            // by the time the lambda is evaluated on RenderThread.
-            renderthread::RenderThread::getInstance().queue().post(
-                    [atlas = mAtlas, atlasKey = mAtlasKey]() {
-                        sp<skiapipeline::VectorDrawableAtlas> lockAtlas = atlas.promote();
-                        if (lockAtlas.get()) {
-                            lockAtlas->releaseEntry(atlasKey);
-                        }
-                    });
-        }
-        mAtlasKey = INVALID_ATLAS_KEY;
-    }
-    mAtlas = nullptr;
-#endif
-}
-
 void Tree::draw(SkCanvas* canvas, const SkRect& bounds, const SkPaint& inPaint) {
     if (canvas->quickReject(bounds)) {
         // The RenderNode is on screen, but the AVD is not.
@@ -587,39 +506,14 @@
     SkPaint paint = inPaint;
     paint.setAlpha(mProperties.getRootAlpha() * 255);
 
-    if (canvas->getGrContext() == nullptr) {
-        // Recording to picture, don't use the SkSurface which won't work off of renderthread.
-        Bitmap& bitmap = getBitmapUpdateIfDirty();
-        SkBitmap skiaBitmap;
-        bitmap.getSkBitmap(&skiaBitmap);
+    Bitmap& bitmap = getBitmapUpdateIfDirty();
+    SkBitmap skiaBitmap;
+    bitmap.getSkBitmap(&skiaBitmap);
 
-        int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth());
-        int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
-        canvas->drawBitmapRect(skiaBitmap, SkRect::MakeWH(scaledWidth, scaledHeight), bounds,
-                               &paint, SkCanvas::kFast_SrcRectConstraint);
-        return;
-    }
-
-    SkRect src;
-    sk_sp<SkSurface> vdSurface = mCache.getSurface(&src);
-    if (vdSurface) {
-        canvas->drawImageRect(vdSurface->makeImageSnapshot().get(), src, bounds, &paint,
-                              SkCanvas::kFast_SrcRectConstraint);
-    } else {
-        // Handle the case when VectorDrawableAtlas has been destroyed, because of memory pressure.
-        // We render the VD into a temporary standalone buffer and mark the frame as dirty. Next
-        // frame will be cached into the atlas.
-        Bitmap& bitmap = getBitmapUpdateIfDirty();
-        SkBitmap skiaBitmap;
-        bitmap.getSkBitmap(&skiaBitmap);
-
-        int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth());
-        int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
-        canvas->drawBitmapRect(skiaBitmap, SkRect::MakeWH(scaledWidth, scaledHeight), bounds,
-                               &paint, SkCanvas::kFast_SrcRectConstraint);
-        mCache.clear();
-        markDirty();
-    }
+    int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth());
+    int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
+    canvas->drawBitmapRect(skiaBitmap, SkRect::MakeWH(scaledWidth, scaledHeight), bounds,
+                           &paint, SkCanvas::kFast_SrcRectConstraint);
 }
 
 void Tree::updateBitmapCache(Bitmap& bitmap, bool useStagingData) {
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index 9c0bb16..e1b6f2a 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -651,46 +651,13 @@
     void getPaintFor(SkPaint* outPaint, const TreeProperties &props) const;
     BitmapPalette computePalette();
 
-    /**
-     * Draws VD into a GPU backed surface.
-     * This should always be called from RT and it works with Skia pipeline only.
-     */
-    void updateCache(sp<skiapipeline::VectorDrawableAtlas>& atlas, GrContext* context);
-
     void setAntiAlias(bool aa) { mRootNode->setAntiAlias(aa); }
 
 private:
     class Cache {
     public:
         sk_sp<Bitmap> bitmap;  // used by HWUI pipeline and software
-        // TODO: use surface instead of bitmap when drawing in software canvas
         bool dirty = true;
-
-        // the rest of the code in Cache is used by Skia pipelines only
-
-        ~Cache() { clear(); }
-
-        /**
-         * Stores a weak pointer to the atlas and a key.
-         */
-        void setAtlas(sp<skiapipeline::VectorDrawableAtlas> atlas,
-                      skiapipeline::AtlasKey newAtlasKey);
-
-        /**
-         * Gets a surface and bounds from the atlas.
-         *
-         * @return nullptr if the altas has been deleted.
-         */
-        sk_sp<SkSurface> getSurface(SkRect* bounds);
-
-        /**
-         * Releases atlas key from the atlas, which makes it available for reuse.
-         */
-        void clear();
-
-    private:
-        wp<skiapipeline::VectorDrawableAtlas> mAtlas;
-        skiapipeline::AtlasKey mAtlasKey = INVALID_ATLAS_KEY;
     };
 
     bool allocateBitmapIfNeeded(Cache& cache, int width, int height);
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index b98ffca..c138a32 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -95,18 +95,10 @@
 
     void operator()(size_t start, size_t end) {
         auto glyphFunc = [&](uint16_t* text, float* positions) {
-            if (canvas->drawTextAbsolutePos()) {
-                for (size_t i = start, textIndex = 0, posIndex = 0; i < end; i++) {
-                    text[textIndex++] = layout.getGlyphId(i);
-                    positions[posIndex++] = x + layout.getX(i);
-                    positions[posIndex++] = y + layout.getY(i);
-                }
-            } else {
-                for (size_t i = start, textIndex = 0, posIndex = 0; i < end; i++) {
-                    text[textIndex++] = layout.getGlyphId(i);
-                    positions[posIndex++] = layout.getX(i);
-                    positions[posIndex++] = layout.getY(i);
-                }
+            for (size_t i = start, textIndex = 0, posIndex = 0; i < end; i++) {
+                text[textIndex++] = layout.getGlyphId(i);
+                positions[posIndex++] = x + layout.getX(i);
+                positions[posIndex++] = y + layout.getY(i);
             }
         };
 
@@ -166,9 +158,6 @@
 
     minikin::MinikinRect bounds;
     layout.getBounds(&bounds);
-    if (!drawTextAbsolutePos()) {
-        bounds.offset(x, y);
-    }
 
     // Set align to left for drawing, as we don't want individual
     // glyphs centered or right-aligned; the offset above takes
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index b90a4a3..27dfed3 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -253,15 +253,6 @@
     virtual void drawPicture(const SkPicture& picture) = 0;
 
     /**
-     * Specifies if the positions passed to ::drawText are absolute or relative
-     * to the (x,y) value provided.
-     *
-     * If true the (x,y) values are ignored. Otherwise, those (x,y) values need
-     * to be added to each glyph's position to get its absolute position.
-     */
-    virtual bool drawTextAbsolutePos() const = 0;
-
-    /**
      * Draws a VectorDrawable onto the canvas.
      */
     virtual void drawVectorDrawable(VectorDrawableRoot* tree) = 0;
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index d7076d4..158c349 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -150,12 +150,7 @@
             const SkRect& bounds = vectorDrawable->properties().getBounds();
             if (intersects(info.screenSize, totalMatrix, bounds)) {
                 isDirty = true;
-#ifdef __ANDROID__ // Layoutlib does not support CanvasContext
-                static_cast<SkiaPipeline*>(info.canvasContext.getRenderPipeline())
-                        ->getVectorDrawables()
-                        ->push_back(vectorDrawable);
                 vectorDrawable->setPropertyChangeWillBeConsumed(true);
-#endif
             }
         }
     }
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 3010206..87ef7fc 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -43,7 +43,6 @@
 namespace skiapipeline {
 
 SkiaPipeline::SkiaPipeline(RenderThread& thread) : mRenderThread(thread) {
-    mVectorDrawables.reserve(30);
 }
 
 SkiaPipeline::~SkiaPipeline() {
@@ -73,18 +72,11 @@
     mPinnedImages.clear();
 }
 
-void SkiaPipeline::onPrepareTree() {
-    // The only time mVectorDrawables is not empty is if prepare tree was called 2 times without
-    // a renderFrame in the middle.
-    mVectorDrawables.clear();
-}
-
 void SkiaPipeline::renderLayers(const LightGeometry& lightGeometry,
                                 LayerUpdateQueue* layerUpdateQueue, bool opaque,
                                 const LightInfo& lightInfo) {
     LightingInfo::updateLighting(lightGeometry, lightInfo);
     ATRACE_NAME("draw layers");
-    renderVectorDrawableCache();
     renderLayersImpl(*layerUpdateQueue, opaque);
     layerUpdateQueue->clear();
 }
@@ -213,19 +205,6 @@
     }
 }
 
-void SkiaPipeline::renderVectorDrawableCache() {
-    if (!mVectorDrawables.empty()) {
-        sp<VectorDrawableAtlas> atlas = mRenderThread.cacheManager().acquireVectorDrawableAtlas();
-        auto grContext = mRenderThread.getGrContext();
-        atlas->prepareForDraw(grContext);
-        ATRACE_NAME("Update VectorDrawables");
-        for (auto vd : mVectorDrawables) {
-            vd->updateCache(atlas, grContext);
-        }
-        mVectorDrawables.clear();
-    }
-}
-
 static void savePictureAsync(const sk_sp<SkData>& data, const std::string& filename) {
     CommonPool::post([data, filename] {
         if (0 == access(filename.c_str(), F_OK)) {
@@ -380,8 +359,6 @@
         Properties::skpCaptureEnabled = true;
     }
 
-    renderVectorDrawableCache();
-
     // draw all layers up front
     renderLayersImpl(layers, opaque);
 
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 37b559f..215ff36 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -41,7 +41,6 @@
     bool pinImages(std::vector<SkImage*>& mutableImages) override;
     bool pinImages(LsaVector<sk_sp<Bitmap>>& images) override { return false; }
     void unpinImages() override;
-    void onPrepareTree() override;
 
     void renderLayers(const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
                       bool opaque, const LightInfo& lightInfo) override;
@@ -57,8 +56,6 @@
                      const Rect& contentDrawBounds, sk_sp<SkSurface> surface,
                      const SkMatrix& preTransform);
 
-    std::vector<VectorDrawableRoot*>* getVectorDrawables() { return &mVectorDrawables; }
-
     static void prepareToDraw(const renderthread::RenderThread& thread, Bitmap* bitmap);
 
     void renderLayersImpl(const LayerUpdateQueue& layers, bool opaque);
@@ -93,11 +90,6 @@
                         const std::vector<sp<RenderNode>>& nodes, const Rect& contentDrawBounds,
                         sk_sp<SkSurface> surface, const SkMatrix& preTransform);
 
-    /**
-     *  Render mVectorDrawables into offscreen buffers.
-     */
-    void renderVectorDrawableCache();
-
     // Called every frame. Normally returns early with screen canvas.
     // But when capture is enabled, returns an nwaycanvas where commands are also recorded.
     SkCanvas* tryCapture(SkSurface* surface);
@@ -113,11 +105,6 @@
 
     std::vector<sk_sp<SkImage>> mPinnedImages;
 
-    /**
-     *  populated by prepareTree with dirty VDs
-     */
-    std::vector<VectorDrawableRoot*> mVectorDrawables;
-
     // Block of properties used only for debugging to record a SkPicture and save it in a file.
     // There are three possible ways of recording drawing commands.
     enum class CaptureMode {
diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp b/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
deleted file mode 100644
index e783f38..0000000
--- a/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#include "VectorDrawableAtlas.h"
-
-#include <GrRectanizer_pow2.h>
-#include <SkCanvas.h>
-#include <cmath>
-#include "renderthread/RenderProxy.h"
-#include "renderthread/RenderThread.h"
-#include "utils/TraceUtils.h"
-
-namespace android {
-namespace uirenderer {
-namespace skiapipeline {
-
-VectorDrawableAtlas::VectorDrawableAtlas(size_t surfaceArea, StorageMode storageMode)
-        : mWidth((int)std::sqrt(surfaceArea))
-        , mHeight((int)std::sqrt(surfaceArea))
-        , mStorageMode(storageMode) {}
-
-void VectorDrawableAtlas::prepareForDraw(GrContext* context) {
-    if (StorageMode::allowSharedSurface == mStorageMode) {
-        if (!mSurface) {
-            mSurface = createSurface(mWidth, mHeight, context);
-            mRectanizer = std::make_unique<GrRectanizerPow2>(mWidth, mHeight);
-            mPixelUsedByVDs = 0;
-            mPixelAllocated = 0;
-            mConsecutiveFailures = 0;
-            mFreeRects.clear();
-        } else {
-            if (isFragmented()) {
-                // Invoke repack outside renderFrame to avoid jank.
-                renderthread::RenderProxy::repackVectorDrawableAtlas();
-            }
-        }
-    }
-}
-
-#define MAX_CONSECUTIVE_FAILURES 5
-#define MAX_UNUSED_RATIO 2.0f
-
-bool VectorDrawableAtlas::isFragmented() {
-    return mConsecutiveFailures > MAX_CONSECUTIVE_FAILURES &&
-           mPixelUsedByVDs * MAX_UNUSED_RATIO < mPixelAllocated;
-}
-
-void VectorDrawableAtlas::repackIfNeeded(GrContext* context) {
-    // We repackage when atlas failed to allocate space MAX_CONSECUTIVE_FAILURES consecutive
-    // times and the atlas allocated pixels are at least MAX_UNUSED_RATIO times higher than pixels
-    // used by atlas VDs.
-    if (isFragmented() && mSurface) {
-        repack(context);
-    }
-}
-
-// compare to CacheEntry objects based on VD area.
-bool VectorDrawableAtlas::compareCacheEntry(const CacheEntry& first, const CacheEntry& second) {
-    return first.VDrect.width() * first.VDrect.height() <
-           second.VDrect.width() * second.VDrect.height();
-}
-
-void VectorDrawableAtlas::repack(GrContext* context) {
-    ATRACE_CALL();
-    sk_sp<SkSurface> newSurface;
-    SkCanvas* canvas = nullptr;
-    if (StorageMode::allowSharedSurface == mStorageMode) {
-        newSurface = createSurface(mWidth, mHeight, context);
-        if (!newSurface) {
-            return;
-        }
-        canvas = newSurface->getCanvas();
-        canvas->clear(SK_ColorTRANSPARENT);
-        mRectanizer = std::make_unique<GrRectanizerPow2>(mWidth, mHeight);
-    } else {
-        if (!mSurface) {
-            return;  // nothing to repack
-        }
-        mRectanizer.reset();
-    }
-    mFreeRects.clear();
-    SkImage* sourceImageAtlas = nullptr;
-    if (mSurface) {
-        sourceImageAtlas = mSurface->makeImageSnapshot().get();
-    }
-
-    // Sort the list by VD size, which allows for the smallest VDs to get first in the atlas.
-    // Sorting is safe, because it does not affect iterator validity.
-    if (mRects.size() <= 100) {
-        mRects.sort(compareCacheEntry);
-    }
-
-    for (CacheEntry& entry : mRects) {
-        SkRect currentVDRect = entry.VDrect;
-        SkImage* sourceImage;  // copy either from the atlas or from a standalone surface
-        if (entry.surface) {
-            if (!fitInAtlas(currentVDRect.width(), currentVDRect.height())) {
-                continue;  // don't even try to repack huge VD
-            }
-            sourceImage = entry.surface->makeImageSnapshot().get();
-        } else {
-            sourceImage = sourceImageAtlas;
-        }
-        size_t VDRectArea = currentVDRect.width() * currentVDRect.height();
-        SkIPoint16 pos;
-        if (canvas && mRectanizer->addRect(currentVDRect.width(), currentVDRect.height(), &pos)) {
-            SkRect newRect =
-                    SkRect::MakeXYWH(pos.fX, pos.fY, currentVDRect.width(), currentVDRect.height());
-            canvas->drawImageRect(sourceImage, currentVDRect, newRect, nullptr);
-            entry.VDrect = newRect;
-            entry.rect = newRect;
-            if (entry.surface) {
-                // A rectangle moved from a standalone surface to the atlas.
-                entry.surface = nullptr;
-                mPixelUsedByVDs += VDRectArea;
-            }
-        } else {
-            // Repack failed for this item. If it is not already, store it in a standalone
-            // surface.
-            if (!entry.surface) {
-                // A rectangle moved from an atlas to a standalone surface.
-                mPixelUsedByVDs -= VDRectArea;
-                SkRect newRect = SkRect::MakeWH(currentVDRect.width(), currentVDRect.height());
-                entry.surface = createSurface(newRect.width(), newRect.height(), context);
-                auto tempCanvas = entry.surface->getCanvas();
-                tempCanvas->clear(SK_ColorTRANSPARENT);
-                tempCanvas->drawImageRect(sourceImageAtlas, currentVDRect, newRect, nullptr);
-                entry.VDrect = newRect;
-                entry.rect = newRect;
-            }
-        }
-    }
-    mPixelAllocated = mPixelUsedByVDs;
-    context->flush();
-    mSurface = newSurface;
-    mConsecutiveFailures = 0;
-}
-
-AtlasEntry VectorDrawableAtlas::requestNewEntry(int width, int height, GrContext* context) {
-    AtlasEntry result;
-    if (width <= 0 || height <= 0) {
-        return result;
-    }
-
-    if (mSurface) {
-        const size_t area = width * height;
-
-        // Use a rectanizer to allocate unused space from the atlas surface.
-        bool notTooBig = fitInAtlas(width, height);
-        SkIPoint16 pos;
-        if (notTooBig && mRectanizer->addRect(width, height, &pos)) {
-            mPixelUsedByVDs += area;
-            mPixelAllocated += area;
-            result.rect = SkRect::MakeXYWH(pos.fX, pos.fY, width, height);
-            result.surface = mSurface;
-            auto eraseIt = mRects.emplace(mRects.end(), result.rect, result.rect, nullptr);
-            CacheEntry* entry = &(*eraseIt);
-            entry->eraseIt = eraseIt;
-            result.key = reinterpret_cast<AtlasKey>(entry);
-            mConsecutiveFailures = 0;
-            return result;
-        }
-
-        // Try to reuse atlas memory from rectangles freed by "releaseEntry".
-        auto freeRectIt = mFreeRects.lower_bound(area);
-        while (freeRectIt != mFreeRects.end()) {
-            SkRect& freeRect = freeRectIt->second;
-            if (freeRect.width() >= width && freeRect.height() >= height) {
-                result.rect = SkRect::MakeXYWH(freeRect.fLeft, freeRect.fTop, width, height);
-                result.surface = mSurface;
-                auto eraseIt = mRects.emplace(mRects.end(), result.rect, freeRect, nullptr);
-                CacheEntry* entry = &(*eraseIt);
-                entry->eraseIt = eraseIt;
-                result.key = reinterpret_cast<AtlasKey>(entry);
-                mPixelUsedByVDs += area;
-                mFreeRects.erase(freeRectIt);
-                mConsecutiveFailures = 0;
-                return result;
-            }
-            freeRectIt++;
-        }
-
-        if (notTooBig && mConsecutiveFailures <= MAX_CONSECUTIVE_FAILURES) {
-            mConsecutiveFailures++;
-        }
-    }
-
-    // Allocate a surface for a rectangle that is too big or if atlas is full.
-    if (nullptr != context) {
-        result.rect = SkRect::MakeWH(width, height);
-        result.surface = createSurface(width, height, context);
-        auto eraseIt = mRects.emplace(mRects.end(), result.rect, result.rect, result.surface);
-        CacheEntry* entry = &(*eraseIt);
-        entry->eraseIt = eraseIt;
-        result.key = reinterpret_cast<AtlasKey>(entry);
-    }
-
-    return result;
-}
-
-AtlasEntry VectorDrawableAtlas::getEntry(AtlasKey atlasKey) {
-    AtlasEntry result;
-    if (INVALID_ATLAS_KEY != atlasKey) {
-        CacheEntry* entry = reinterpret_cast<CacheEntry*>(atlasKey);
-        result.rect = entry->VDrect;
-        result.surface = entry->surface;
-        if (!result.surface) {
-            result.surface = mSurface;
-        }
-        result.key = atlasKey;
-    }
-    return result;
-}
-
-void VectorDrawableAtlas::releaseEntry(AtlasKey atlasKey) {
-    if (INVALID_ATLAS_KEY != atlasKey) {
-        if (!renderthread::RenderThread::isCurrent()) {
-            {
-                AutoMutex _lock(mReleaseKeyLock);
-                mKeysForRelease.push_back(atlasKey);
-            }
-            // invoke releaseEntry on the renderthread
-            renderthread::RenderProxy::releaseVDAtlasEntries();
-            return;
-        }
-        CacheEntry* entry = reinterpret_cast<CacheEntry*>(atlasKey);
-        if (!entry->surface) {
-            // Store freed atlas rectangles in "mFreeRects" and try to reuse them later, when atlas
-            // is full.
-            SkRect& removedRect = entry->rect;
-            size_t rectArea = removedRect.width() * removedRect.height();
-            mFreeRects.emplace(rectArea, removedRect);
-            SkRect& removedVDRect = entry->VDrect;
-            size_t VDRectArea = removedVDRect.width() * removedVDRect.height();
-            mPixelUsedByVDs -= VDRectArea;
-            mConsecutiveFailures = 0;
-        }
-        auto eraseIt = entry->eraseIt;
-        mRects.erase(eraseIt);
-    }
-}
-
-void VectorDrawableAtlas::delayedReleaseEntries() {
-    AutoMutex _lock(mReleaseKeyLock);
-    for (auto key : mKeysForRelease) {
-        releaseEntry(key);
-    }
-    mKeysForRelease.clear();
-}
-
-sk_sp<SkSurface> VectorDrawableAtlas::createSurface(int width, int height, GrContext* context) {
-    SkImageInfo info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType);
-    // This must have a top-left origin so that calls to surface->canvas->writePixels
-    // performs a basic texture upload instead of a more complex drawing operation
-    return SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 0, kTopLeft_GrSurfaceOrigin,
-                                       nullptr);
-}
-
-void VectorDrawableAtlas::setStorageMode(StorageMode mode) {
-    mStorageMode = mode;
-    if (StorageMode::disallowSharedSurface == mStorageMode && mSurface) {
-        mSurface.reset();
-        mRectanizer.reset();
-        mFreeRects.clear();
-    }
-}
-
-} /* namespace skiapipeline */
-} /* namespace uirenderer */
-} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h b/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
deleted file mode 100644
index 5e892aa..0000000
--- a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#pragma once
-
-#include <SkSurface.h>
-#include <utils/FatVector.h>
-#include <utils/RefBase.h>
-#include <utils/Thread.h>
-#include <list>
-#include <map>
-
-class GrRectanizer;
-
-namespace android {
-namespace uirenderer {
-namespace skiapipeline {
-
-typedef uintptr_t AtlasKey;
-
-#define INVALID_ATLAS_KEY 0
-
-struct AtlasEntry {
-    sk_sp<SkSurface> surface;
-    SkRect rect;
-    AtlasKey key = INVALID_ATLAS_KEY;
-};
-
-/**
- * VectorDrawableAtlas provides offscreen buffers used to draw VD and AnimatedVD.
- * VectorDrawableAtlas can allocate a standalone surface or provide a subrect from a shared surface.
- * VectorDrawableAtlas is owned by the CacheManager and weak pointers are kept by each
- * VectorDrawable that is using it. VectorDrawableAtlas and its surface can be deleted at any time,
- * except during a renderFrame call. VectorDrawable does not contain a pointer to atlas SkSurface
- * nor any coordinates into the atlas, but instead holds a rectangle "id", which is resolved only
- * when drawing. This design makes VectorDrawableAtlas free to move the data internally.
- * At draw time a VectorDrawable may find, that its atlas has been deleted, which will make it
- * draw in a standalone cache surface not part of an atlas. In this case VD won't use
- * VectorDrawableAtlas until the next frame.
- * VectorDrawableAtlas tries to fit VDs in the atlas SkSurface. If there is not enough space in
- * the atlas, VectorDrawableAtlas creates a standalone surface for each VD.
- * When a VectorDrawable is deleted, it invokes VectorDrawableAtlas::releaseEntry, which is keeping
- * track of free spaces and allow to reuse the surface for another VD.
- */
-// TODO: Check if not using atlas for AnimatedVD is more efficient.
-// TODO: For low memory situations, when there are no paint effects in VD, we may render without an
-// TODO: offscreen surface.
-class VectorDrawableAtlas : public virtual RefBase {
-public:
-    enum class StorageMode { allowSharedSurface, disallowSharedSurface };
-
-    explicit VectorDrawableAtlas(size_t surfaceArea,
-                                 StorageMode storageMode = StorageMode::allowSharedSurface);
-
-    /**
-     * "prepareForDraw" may allocate a new surface if needed. It may schedule to repack the
-     * atlas at a later time.
-     */
-    void prepareForDraw(GrContext* context);
-
-    /**
-     * Repack the atlas if needed, by moving used rectangles into a new atlas surface.
-     * The goal of repacking is to fix a fragmented atlas.
-     */
-    void repackIfNeeded(GrContext* context);
-
-    /**
-     * Returns true if atlas is fragmented and repack is needed.
-     */
-    bool isFragmented();
-
-    /**
-     * "requestNewEntry" is called by VectorDrawable to allocate a new rectangle area from the atlas
-     * or create a standalone surface if atlas is full.
-     * On success it returns a non-negative unique id, which can be used later with "getEntry" and
-     * "releaseEntry".
-     */
-    AtlasEntry requestNewEntry(int width, int height, GrContext* context);
-
-    /**
-     * "getEntry" extracts coordinates and surface of a previously created rectangle.
-     * "atlasKey" is an unique id created by "requestNewEntry". Passing a non-existing "atlasKey" is
-     * causing an undefined behaviour.
-     * On success it returns a rectangle Id -> may be same or different from "atlasKey" if
-     * implementation decides to move the record internally.
-     */
-    AtlasEntry getEntry(AtlasKey atlasKey);
-
-    /**
-     * "releaseEntry" is invoked when a VectorDrawable is deleted. Passing a non-existing "atlasKey"
-     * is causing an undefined behaviour. This is the only function in the class that can be
-     * invoked from any thread. It will marshal internally to render thread if needed.
-     */
-    void releaseEntry(AtlasKey atlasKey);
-
-    void setStorageMode(StorageMode mode);
-
-    /**
-     * "delayedReleaseEntries" is indirectly invoked by "releaseEntry", when "releaseEntry" is
-     * invoked from a non render thread.
-     */
-    void delayedReleaseEntries();
-
-private:
-    struct CacheEntry {
-        CacheEntry(const SkRect& newVDrect, const SkRect& newRect,
-                   const sk_sp<SkSurface>& newSurface)
-                : VDrect(newVDrect), rect(newRect), surface(newSurface) {}
-
-        /**
-         * size and position of VectorDrawable into the atlas or in "this.surface"
-         */
-        SkRect VDrect;
-
-        /**
-         * rect allocated in atlas surface or "this.surface". It may be bigger than "VDrect"
-         */
-        SkRect rect;
-
-        /**
-         * this surface is used if atlas is full or VD is too big
-         */
-        sk_sp<SkSurface> surface;
-
-        /**
-         * iterator is used to delete self with a constant complexity (without traversing the list)
-         */
-        std::list<CacheEntry>::iterator eraseIt;
-    };
-
-    /**
-     * atlas surface shared by all VDs
-     */
-    sk_sp<SkSurface> mSurface;
-
-    std::unique_ptr<GrRectanizer> mRectanizer;
-    const int mWidth;
-    const int mHeight;
-
-    /**
-     * "mRects" keeps records only for rectangles used by VDs. List has nice properties: constant
-     * complexity to insert and erase and references are not invalidated by insert/erase.
-     */
-    std::list<CacheEntry> mRects;
-
-    /**
-     * Rectangles freed by "releaseEntry" are removed from "mRects" and added to "mFreeRects".
-     * "mFreeRects" is using for an index the rectangle area. There could be more than one free
-     * rectangle with the same area, which is the reason to use "multimap" instead of "map".
-     */
-    std::multimap<size_t, SkRect> mFreeRects;
-
-    /**
-     * area in atlas used by VectorDrawables (area in standalone surface not counted)
-     */
-    int mPixelUsedByVDs = 0;
-
-    /**
-     * area allocated in mRectanizer
-     */
-    int mPixelAllocated = 0;
-
-    /**
-     * Consecutive times we had to allocate standalone surfaces, because atlas was full.
-     */
-    int mConsecutiveFailures = 0;
-
-    /**
-     * mStorageMode allows using a shared surface to store small vector drawables.
-     * Using a shared surface can boost the performance by allowing GL ops to be batched, but may
-     * consume more memory.
-     */
-    StorageMode mStorageMode;
-
-    /**
-     * mKeysForRelease is used by releaseEntry implementation to pass atlas keys from an arbitrary
-     * calling thread to the render thread.
-     */
-    std::vector<AtlasKey> mKeysForRelease;
-
-    /**
-     * A lock used to protect access to mKeysForRelease.
-     */
-    Mutex mReleaseKeyLock;
-
-    sk_sp<SkSurface> createSurface(int width, int height, GrContext* context);
-
-    inline bool fitInAtlas(int width, int height) {
-        return 2 * width < mWidth && 2 * height < mHeight;
-    }
-
-    void repack(GrContext* context);
-
-    static bool compareCacheEntry(const CacheEntry& first, const CacheEntry& second);
-};
-
-} /* namespace skiapipeline */
-} /* namespace uirenderer */
-} /* namespace android */
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 8eb8153..b366a80 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -56,10 +56,6 @@
         , mBackgroundCpuFontCacheBytes(mMaxCpuFontCacheBytes * BACKGROUND_RETENTION_PERCENTAGE) {
 
     SkGraphics::SetFontCacheLimit(mMaxCpuFontCacheBytes);
-
-    mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(
-            mMaxSurfaceArea / 2,
-            skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface);
 }
 
 void CacheManager::reset(sk_sp<GrContext> context) {
@@ -76,9 +72,6 @@
 void CacheManager::destroy() {
     // cleanup any caches here as the GrContext is about to go away...
     mGrContext.reset(nullptr);
-    mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(
-            mMaxSurfaceArea / 2,
-            skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface);
 }
 
 class CommonPoolExecutor : public SkExecutor {
@@ -109,7 +102,6 @@
 
     switch (mode) {
         case TrimMemoryMode::Complete:
-            mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea / 2);
             mGrContext->freeGpuResources();
             SkGraphics::PurgeAllCaches();
             break;
@@ -138,16 +130,6 @@
     mGrContext->purgeResourcesNotUsedInMs(std::chrono::seconds(30));
 }
 
-sp<skiapipeline::VectorDrawableAtlas> CacheManager::acquireVectorDrawableAtlas() {
-    LOG_ALWAYS_FATAL_IF(mVectorDrawableAtlas.get() == nullptr);
-    LOG_ALWAYS_FATAL_IF(mGrContext == nullptr);
-
-    /**
-     * TODO: define memory conditions where we clear the cache (e.g. surface->reset())
-     */
-    return mVectorDrawableAtlas;
-}
-
 void CacheManager::dumpMemoryUsage(String8& log, const RenderState* renderState) {
     if (!mGrContext) {
         log.appendFormat("No valid cache instance.\n");
@@ -176,8 +158,6 @@
 
     log.appendFormat("Other Caches:\n");
     log.appendFormat("                         Current / Maximum\n");
-    log.appendFormat("  VectorDrawableAtlas  %6.2f kB / %6.2f KB (entries = %zu)\n", 0.0f, 0.0f,
-                     (size_t)0);
 
     if (renderState) {
         if (renderState->mActiveLayers.size() > 0) {
diff --git a/libs/hwui/renderthread/CacheManager.h b/libs/hwui/renderthread/CacheManager.h
index d7977cc..857710b 100644
--- a/libs/hwui/renderthread/CacheManager.h
+++ b/libs/hwui/renderthread/CacheManager.h
@@ -25,8 +25,6 @@
 #include <utils/String8.h>
 #include <vector>
 
-#include "pipeline/skia/VectorDrawableAtlas.h"
-
 namespace android {
 
 class Surface;
@@ -51,8 +49,6 @@
     void trimStaleResources();
     void dumpMemoryUsage(String8& log, const RenderState* renderState = nullptr);
 
-    sp<skiapipeline::VectorDrawableAtlas> acquireVectorDrawableAtlas();
-
     size_t getCacheSize() const { return mMaxResourceBytes; }
     size_t getBackgroundCacheSize() const { return mBackgroundResourceBytes; }
 
@@ -77,13 +73,6 @@
     const size_t mMaxGpuFontAtlasBytes;
     const size_t mMaxCpuFontCacheBytes;
     const size_t mBackgroundCpuFontCacheBytes;
-
-    struct PipelineProps {
-        const void* pipelineKey = nullptr;
-        size_t surfaceArea = 0;
-    };
-
-    sp<skiapipeline::VectorDrawableAtlas> mVectorDrawableAtlas;
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 30cc007..15e0c8d 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -303,10 +303,10 @@
 
     info.damageAccumulator = &mDamageAccumulator;
     info.layerUpdateQueue = &mLayerUpdateQueue;
+    info.damageGenerationId = mDamageId++;
     info.out.canDrawThisFrame = true;
 
     mAnimationContext->startFrame(info.mode);
-    mRenderPipeline->onPrepareTree();
     for (const sp<RenderNode>& node : mRenderNodes) {
         // Only the primary target node will be drawn full - all other nodes would get drawn in
         // real time mode. In case of a window, the primary node is the window content and the other
@@ -479,7 +479,8 @@
         if (didDraw) {
             swap.damage = windowDirty;
         } else {
-            swap.damage = SkRect::MakeWH(INT_MAX, INT_MAX);
+            float max = static_cast<float>(INT_MAX);
+            swap.damage = SkRect::MakeWH(max, max);
         }
         swap.swapCompletedTime = systemTime(SYSTEM_TIME_MONOTONIC);
         swap.vsyncTime = mRenderThread.timeLord().latestVsync();
@@ -565,8 +566,8 @@
     ReliableSurface* surface = mNativeSurface.get();
     if (surface) {
         SkISize size;
-        surface->query(NATIVE_WINDOW_WIDTH, &size.fWidth);
-        surface->query(NATIVE_WINDOW_HEIGHT, &size.fHeight);
+        size.fWidth = ANativeWindow_getWidth(surface);
+        size.fHeight = ANativeWindow_getHeight(surface);
         return size;
     }
     return {INT32_MAX, INT32_MAX};
@@ -703,7 +704,7 @@
     surface->query(NATIVE_WINDOW_WIDTH, &width);
     surface->query(NATIVE_WINDOW_HEIGHT, &height);
 
-    return width == mLastFrameWidth && height == mLastFrameHeight;
+    return width != mLastFrameWidth || height != mLastFrameHeight;
 }
 
 void CanvasContext::setRenderAheadDepth(int renderAhead) {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 8a76d6b..b192d46 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -242,8 +242,10 @@
         nsecs_t queueDuration;
     };
 
-    RingBuffer<SwapHistory, 3> mSwapHistory;
+    // Need at least 4 because we do quad buffer. Add a 5th for good measure.
+    RingBuffer<SwapHistory, 5> mSwapHistory;
     int64_t mFrameNumber = -1;
+    int64_t mDamageId = 0;
 
     // last vsync for a dropped frame due to stuffed queue
     nsecs_t mLastDropVsync = 0;
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index 3b81014..ef0aa98 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -80,7 +80,6 @@
     virtual bool pinImages(std::vector<SkImage*>& mutableImages) = 0;
     virtual bool pinImages(LsaVector<sk_sp<Bitmap>>& images) = 0;
     virtual void unpinImages() = 0;
-    virtual void onPrepareTree() = 0;
     virtual SkColorType getSurfaceColorType() const = 0;
     virtual sk_sp<SkColorSpace> getSurfaceColorSpace() = 0;
     virtual GrSurfaceOrigin getSurfaceOrigin() = 0;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 40fbdff..4f7ad7b 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -24,7 +24,6 @@
 #include "Readback.h"
 #include "Rect.h"
 #include "WebViewFunctorManager.h"
-#include "pipeline/skia/VectorDrawableAtlas.h"
 #include "renderthread/CanvasContext.h"
 #include "renderthread/RenderTask.h"
 #include "renderthread/RenderThread.h"
@@ -365,27 +364,6 @@
     Properties::disableVsync = true;
 }
 
-void RenderProxy::repackVectorDrawableAtlas() {
-    RenderThread& thread = RenderThread::getInstance();
-    thread.queue().post([&thread]() {
-        // The context may be null if trimMemory executed, but then the atlas was deleted too.
-        if (thread.getGrContext() != nullptr) {
-            thread.cacheManager().acquireVectorDrawableAtlas()->repackIfNeeded(
-                    thread.getGrContext());
-        }
-    });
-}
-
-void RenderProxy::releaseVDAtlasEntries() {
-    RenderThread& thread = RenderThread::getInstance();
-    thread.queue().post([&thread]() {
-        // The context may be null if trimMemory executed, but then the atlas was deleted too.
-        if (thread.getGrContext() != nullptr) {
-            thread.cacheManager().acquireVectorDrawableAtlas()->delayedReleaseEntries();
-        }
-    });
-}
-
 void RenderProxy::preload() {
     // Create RenderThread object and start the thread. Then preload Vulkan/EGL driver.
     auto& thread = RenderThread::getInstance();
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index c3eb6ed..e6fe1d4 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -150,10 +150,6 @@
 
     ANDROID_API static void preload();
 
-    static void repackVectorDrawableAtlas();
-
-    static void releaseVDAtlasEntries();
-
 private:
     RenderThread& mRenderThread;
     CanvasContext* mContext;
diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
index 6fb164a..7d999c4 100644
--- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
+++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
@@ -208,9 +208,8 @@
     test::TestContext testContext;
     testContext.setRenderOffscreen(true);
     auto surface = testContext.surface();
-    int width, height;
-    surface->query(NATIVE_WINDOW_WIDTH, &width);
-    surface->query(NATIVE_WINDOW_HEIGHT, &height);
+    int width = ANativeWindow_getWidth(surface.get());
+    int height = ANativeWindow_getHeight(surface.get());
     canvasContext->setSurface(std::move(surface));
 
     TreeInfo info(TreeInfo::MODE_FULL, *canvasContext.get());
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 958baa7..307d136 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -61,39 +61,6 @@
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
 }
 
-RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, testOnPrepareTree) {
-    auto redNode = TestUtils::createSkiaNode(
-            0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
-                redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
-            });
-
-    LayerUpdateQueue layerUpdateQueue;
-    SkRect dirty = SkRectMakeLargest();
-    std::vector<sp<RenderNode>> renderNodes;
-    renderNodes.push_back(redNode);
-    bool opaque = true;
-    android::uirenderer::Rect contentDrawBounds(0, 0, 1, 1);
-    auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
-    {
-        // add a pointer to a deleted vector drawable object in the pipeline
-        sp<VectorDrawableRoot> dirtyVD(new VectorDrawableRoot(new VectorDrawable::Group()));
-        dirtyVD->mutateProperties()->setScaledSize(5, 5);
-        pipeline->getVectorDrawables()->push_back(dirtyVD.get());
-    }
-
-    // pipeline should clean list of dirty vector drawables before prepare tree
-    pipeline->onPrepareTree();
-
-    auto surface = SkSurface::MakeRasterN32Premul(1, 1);
-    surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
-    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
-
-    // drawFrame will crash if "SkiaPipeline::onPrepareTree" did not clean invalid VD pointer
-    pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface,
-            SkMatrix::I());
-    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
-}
-
 RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) {
     auto halfGreenNode = TestUtils::createSkiaNode(
             0, 0, 2, 2, [](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) {
diff --git a/libs/hwui/tests/unit/VectorDrawableAtlasTests.cpp b/libs/hwui/tests/unit/VectorDrawableAtlasTests.cpp
deleted file mode 100644
index 0c95fdd..0000000
--- a/libs/hwui/tests/unit/VectorDrawableAtlasTests.cpp
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#include <gtest/gtest.h>
-
-#include <GrRectanizer.h>
-#include "pipeline/skia/VectorDrawableAtlas.h"
-#include "tests/common/TestUtils.h"
-
-using namespace android;
-using namespace android::uirenderer;
-using namespace android::uirenderer::renderthread;
-using namespace android::uirenderer::skiapipeline;
-
-RENDERTHREAD_SKIA_PIPELINE_TEST(VectorDrawableAtlas, addGetRemove) {
-    VectorDrawableAtlas atlas(100 * 100);
-    atlas.prepareForDraw(renderThread.getGrContext());
-    // create 150 rects 10x10, which won't fit in the atlas (atlas can fit no more than 100 rects)
-    const int MAX_RECTS = 150;
-    AtlasEntry VDRects[MAX_RECTS];
-
-    sk_sp<SkSurface> atlasSurface;
-
-    // check we are able to allocate new rects
-    // check that rects in the atlas do not intersect
-    for (uint32_t i = 0; i < MAX_RECTS; i++) {
-        VDRects[i] = atlas.requestNewEntry(10, 10, renderThread.getGrContext());
-        if (0 == i) {
-            atlasSurface = VDRects[0].surface;
-        }
-        ASSERT_TRUE(VDRects[i].key != INVALID_ATLAS_KEY);
-        ASSERT_TRUE(VDRects[i].surface.get() != nullptr);
-        ASSERT_TRUE(VDRects[i].rect.width() == 10 && VDRects[i].rect.height() == 10);
-
-        // nothing in the atlas should intersect
-        if (atlasSurface.get() == VDRects[i].surface.get()) {
-            for (uint32_t j = 0; j < i; j++) {
-                if (atlasSurface.get() == VDRects[j].surface.get()) {
-                    ASSERT_FALSE(VDRects[i].rect.intersect(VDRects[j].rect));
-                }
-            }
-        }
-    }
-
-    // first 1/3 rects should all be in the same surface
-    for (uint32_t i = 1; i < MAX_RECTS / 3; i++) {
-        ASSERT_NE(VDRects[i].key, VDRects[0].key);
-        ASSERT_EQ(VDRects[i].surface.get(), atlasSurface.get());
-    }
-
-    // first rect is using atlas and last is a standalone surface
-    ASSERT_NE(VDRects[0].surface.get(), VDRects[MAX_RECTS - 1].surface.get());
-
-    // check getEntry returns the same surfaces that we had created
-    for (uint32_t i = 0; i < MAX_RECTS; i++) {
-        auto VDRect = atlas.getEntry(VDRects[i].key);
-        ASSERT_TRUE(VDRect.key != INVALID_ATLAS_KEY);
-        ASSERT_EQ(VDRects[i].key, VDRect.key);
-        ASSERT_EQ(VDRects[i].surface.get(), VDRect.surface.get());
-        ASSERT_EQ(VDRects[i].rect, VDRect.rect);
-        atlas.releaseEntry(VDRect.key);
-    }
-
-    // check that any new rects will be allocated in the atlas, even that rectanizer is full.
-    // rects in the atlas should not intersect.
-    for (uint32_t i = 0; i < MAX_RECTS / 3; i++) {
-        VDRects[i] = atlas.requestNewEntry(10, 10, renderThread.getGrContext());
-        ASSERT_TRUE(VDRects[i].key != INVALID_ATLAS_KEY);
-        ASSERT_EQ(VDRects[i].surface.get(), atlasSurface.get());
-        ASSERT_TRUE(VDRects[i].rect.width() == 10 && VDRects[i].rect.height() == 10);
-        for (uint32_t j = 0; j < i; j++) {
-            ASSERT_FALSE(VDRects[i].rect.intersect(VDRects[j].rect));
-        }
-    }
-}
-
-RENDERTHREAD_SKIA_PIPELINE_TEST(VectorDrawableAtlas, disallowSharedSurface) {
-    VectorDrawableAtlas atlas(100 * 100);
-    // don't allow to use a shared surface
-    atlas.setStorageMode(VectorDrawableAtlas::StorageMode::disallowSharedSurface);
-    atlas.prepareForDraw(renderThread.getGrContext());
-    // create 150 rects 10x10, which won't fit in the atlas (atlas can fit no more than 100 rects)
-    const int MAX_RECTS = 150;
-    AtlasEntry VDRects[MAX_RECTS];
-
-    // check we are able to allocate new rects
-    // check that rects in the atlas use unique surfaces
-    for (uint32_t i = 0; i < MAX_RECTS; i++) {
-        VDRects[i] = atlas.requestNewEntry(10, 10, renderThread.getGrContext());
-        ASSERT_TRUE(VDRects[i].key != INVALID_ATLAS_KEY);
-        ASSERT_TRUE(VDRects[i].surface.get() != nullptr);
-        ASSERT_TRUE(VDRects[i].rect.width() == 10 && VDRects[i].rect.height() == 10);
-
-        // nothing in the atlas should use the same surface
-        for (uint32_t j = 0; j < i; j++) {
-            ASSERT_NE(VDRects[i].surface.get(), VDRects[j].surface.get());
-        }
-    }
-}
-
-RENDERTHREAD_SKIA_PIPELINE_TEST(VectorDrawableAtlas, repack) {
-    VectorDrawableAtlas atlas(100 * 100);
-    ASSERT_FALSE(atlas.isFragmented());
-    atlas.prepareForDraw(renderThread.getGrContext());
-    ASSERT_FALSE(atlas.isFragmented());
-    // create 150 rects 10x10, which won't fit in the atlas (atlas can fit no more than 100 rects)
-    const int MAX_RECTS = 150;
-    AtlasEntry VDRects[MAX_RECTS];
-
-    sk_sp<SkSurface> atlasSurface;
-
-    // fill the atlas with check we are able to allocate new rects
-    for (uint32_t i = 0; i < MAX_RECTS; i++) {
-        VDRects[i] = atlas.requestNewEntry(10, 10, renderThread.getGrContext());
-        if (0 == i) {
-            atlasSurface = VDRects[0].surface;
-        }
-        ASSERT_TRUE(VDRects[i].key != INVALID_ATLAS_KEY);
-    }
-
-    ASSERT_FALSE(atlas.isFragmented());
-
-    // first 1/3 rects should all be in the same surface
-    for (uint32_t i = 1; i < MAX_RECTS / 3; i++) {
-        ASSERT_NE(VDRects[i].key, VDRects[0].key);
-        ASSERT_EQ(VDRects[i].surface.get(), atlasSurface.get());
-    }
-
-    // release all entries
-    for (uint32_t i = 0; i < MAX_RECTS; i++) {
-        auto VDRect = atlas.getEntry(VDRects[i].key);
-        ASSERT_TRUE(VDRect.key != INVALID_ATLAS_KEY);
-        atlas.releaseEntry(VDRect.key);
-    }
-
-    ASSERT_FALSE(atlas.isFragmented());
-
-    // allocate 4x4 rects, which will fragment the atlas badly, because each entry occupies a 10x10
-    // area
-    for (uint32_t i = 0; i < 4 * MAX_RECTS; i++) {
-        AtlasEntry entry = atlas.requestNewEntry(4, 4, renderThread.getGrContext());
-        ASSERT_TRUE(entry.key != INVALID_ATLAS_KEY);
-    }
-
-    ASSERT_TRUE(atlas.isFragmented());
-
-    atlas.repackIfNeeded(renderThread.getGrContext());
-
-    ASSERT_FALSE(atlas.isFragmented());
-}
\ No newline at end of file
diff --git a/location/TEST_MAPPING b/location/TEST_MAPPING
new file mode 100644
index 0000000..2f38627
--- /dev/null
+++ b/location/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLocationCoarseTestCases"
+    },
+    {
+      "name": "CtsLocationNoneTestCases"
+    }
+  ]
+}
diff --git a/location/java/android/location/ILocationListener.aidl b/location/java/android/location/ILocationListener.aidl
index ec11345..8479caf 100644
--- a/location/java/android/location/ILocationListener.aidl
+++ b/location/java/android/location/ILocationListener.aidl
@@ -31,8 +31,6 @@
     void onProviderEnabled(String provider);
     @UnsupportedAppUsage
     void onProviderDisabled(String provider);
-
-    // --- deprecated ---
-    @UnsupportedAppUsage
-    void onStatusChanged(String provider, int status, in Bundle extras);
+    // called when the listener is removed from the server side; no further callbacks are expected
+    void onRemoved();
 }
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 91f3a20..79bec92 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -42,20 +42,23 @@
  */
 interface ILocationManager
 {
-    Location getLastLocation(in LocationRequest request, String packageName);
+    Location getLastLocation(in LocationRequest request, String packageName, String featureId);
     boolean getCurrentLocation(in LocationRequest request,
             in ICancellationSignal cancellationSignal, in ILocationListener listener,
-            String packageName, String listenerIdentifier);
+            String packageName, String featureId, String listenerIdentifier);
 
     void requestLocationUpdates(in LocationRequest request, in ILocationListener listener,
-            in PendingIntent intent, String packageName, String listenerIdentifier);
+            in PendingIntent intent, String packageName, String featureId,
+            String listenerIdentifier);
     void removeUpdates(in ILocationListener listener, in PendingIntent intent, String packageName);
 
     void requestGeofence(in LocationRequest request, in Geofence geofence,
-            in PendingIntent intent, String packageName, String listenerIdentifier);
+            in PendingIntent intent, String packageName, String featureId,
+            String listenerIdentifier);
     void removeGeofence(in Geofence fence, in PendingIntent intent, String packageName);
 
-    boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName);
+    boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName,
+            String featureId);
     void unregisterGnssStatusCallback(IGnssStatusListener callback);
 
     boolean geocoderIsPresent();
@@ -69,14 +72,14 @@
     boolean sendNiResponse(int notifId, int userResponse);
 
     boolean addGnssMeasurementsListener(in IGnssMeasurementsListener listener,
-             String packageName, String listenerIdentifier);
+             String packageName, String featureId, String listenerIdentifier);
     void injectGnssMeasurementCorrections(in GnssMeasurementCorrections corrections,
             in String packageName);
     long getGnssCapabilities(in String packageName);
     void removeGnssMeasurementsListener(in IGnssMeasurementsListener listener);
 
     boolean addGnssNavigationMessageListener(in IGnssNavigationMessageListener listener,
-             String packageName, String listenerIdentifier);
+             String packageName, String featureId, String listenerIdentifier);
     void removeGnssNavigationMessageListener(in IGnssNavigationMessageListener listener);
 
     int getGnssYearOfHardware();
@@ -84,7 +87,7 @@
 
     int getGnssBatchSize(String packageName);
     boolean addGnssBatchingCallback(in IBatchedLocationCallback callback, String packageName,
-             String listenerIdentifier);
+             String featureId, String listenerIdentifier);
     void removeGnssBatchingCallback();
     boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName);
     void flushGnssBatch(String packageName);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 9e17e95..b7dd543 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -230,7 +230,7 @@
     public static final String METADATA_SETTINGS_FOOTER_STRING =
             "com.android.settings.location.FOOTER_STRING";
 
-    private static final long GET_CURRENT_LOCATION_TIMEOUT_MS = 30 * 1000;
+    private static final long GET_CURRENT_LOCATION_MAX_TIMEOUT_MS = 30 * 1000;
 
     private final Context mContext;
 
@@ -515,7 +515,8 @@
     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
     public Location getLastLocation() {
         try {
-            return mService.getLastLocation(null, mContext.getPackageName());
+            return mService.getLastLocation(null, mContext.getPackageName(),
+                    mContext.getFeatureId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -547,7 +548,8 @@
                 provider, 0, 0, true);
 
         try {
-            return mService.getLastLocation(request, mContext.getPackageName());
+            return mService.getLastLocation(request, mContext.getPackageName(),
+                    mContext.getFeatureId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -628,7 +630,10 @@
             @Nullable CancellationSignal cancellationSignal,
             @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Location> consumer) {
         LocationRequest currentLocationRequest = new LocationRequest(locationRequest)
-                .setNumUpdates(1).setExpireIn(GET_CURRENT_LOCATION_TIMEOUT_MS);
+                .setNumUpdates(1);
+        if (currentLocationRequest.getExpireIn() > GET_CURRENT_LOCATION_MAX_TIMEOUT_MS) {
+            currentLocationRequest.setExpireIn(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS);
+        }
 
         GetCurrentLocationTransport listenerTransport = new GetCurrentLocationTransport(executor,
                 consumer);
@@ -641,7 +646,7 @@
 
         try {
             if (mService.getCurrentLocation(currentLocationRequest, remoteCancellationSignal,
-                    listenerTransport, mContext.getPackageName(),
+                    listenerTransport, mContext.getPackageName(), mContext.getFeatureId(),
                     getListenerIdentifier(consumer))) {
                 listenerTransport.register(mContext.getSystemService(AlarmManager.class),
                         remoteCancellationSignal);
@@ -682,6 +687,7 @@
 
         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
                 provider, 0, 0, true);
+        request.setExpireIn(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS);
         requestLocationUpdates(request, listener, looper);
     }
 
@@ -702,6 +708,7 @@
      * @deprecated Use {@link #getCurrentLocation(String, CancellationSignal, Executor, Consumer)}
      * instead as it does not carry a risk of extreme battery drain.
      */
+    @Deprecated
     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
     public void requestSingleUpdate(
             @NonNull Criteria criteria,
@@ -712,6 +719,7 @@
 
         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
                 criteria, 0, 0, true);
+        request.setExpireIn(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS);
         requestLocationUpdates(request, listener, looper);
     }
 
@@ -730,6 +738,7 @@
      * @deprecated Use {@link #getCurrentLocation(String, CancellationSignal, Executor, Consumer)}
      * instead as it does not carry a risk of extreme battery drain.
      */
+    @Deprecated
     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
     public void requestSingleUpdate(@NonNull String provider,
             @NonNull PendingIntent pendingIntent) {
@@ -738,6 +747,7 @@
 
         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
                 provider, 0, 0, true);
+        request.setExpireIn(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS);
         requestLocationUpdates(request, pendingIntent);
     }
 
@@ -757,6 +767,7 @@
      * @deprecated Use {@link #getCurrentLocation(String, CancellationSignal, Executor, Consumer)}
      * instead as it does not carry a risk of extreme battery drain.
      */
+    @Deprecated
     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
     public void requestSingleUpdate(@NonNull Criteria criteria,
             @NonNull PendingIntent pendingIntent) {
@@ -765,6 +776,7 @@
 
         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
                 criteria, 0, 0, true);
+        request.setExpireIn(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS);
         requestLocationUpdates(request, pendingIntent);
     }
 
@@ -1085,7 +1097,8 @@
             boolean registered = false;
             try {
                 mService.requestLocationUpdates(locationRequest, transport, null,
-                        mContext.getPackageName(), getListenerIdentifier(listener));
+                        mContext.getPackageName(), mContext.getFeatureId(),
+                        getListenerIdentifier(listener));
                 registered = true;
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
@@ -1130,7 +1143,8 @@
 
         try {
             mService.requestLocationUpdates(locationRequest, null, pendingIntent,
-                    mContext.getPackageName(), getListenerIdentifier(pendingIntent));
+                    mContext.getPackageName(), mContext.getFeatureId(),
+                    getListenerIdentifier(pendingIntent));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1594,7 +1608,7 @@
         LocationRequest request = new LocationRequest().setExpireIn(expiration);
         try {
             mService.requestGeofence(request, fence, intent, mContext.getPackageName(),
-                    getListenerIdentifier(intent));
+                    mContext.getFeatureId(), getListenerIdentifier(intent));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1672,7 +1686,7 @@
 
         try {
             mService.requestGeofence(request, fence, intent, mContext.getPackageName(),
-                    getListenerIdentifier(intent));
+                    mContext.getFeatureId(), getListenerIdentifier(intent));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1831,7 +1845,7 @@
         }
 
         try {
-            return mGnssStatusListenerManager.addListener(listener, new Handler());
+            return mGnssStatusListenerManager.addListener(listener, Runnable::run);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2179,7 +2193,7 @@
     public void removeGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {}
 
     /**
-     * Registers a GNSS Navigation Message callback.
+     * Registers a GNSS Navigation Message callback which will run on a binder thread.
      *
      * @param callback a {@link GnssNavigationMessage.Callback} object to register.
      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
@@ -2190,7 +2204,7 @@
     @Deprecated
     public boolean registerGnssNavigationMessageCallback(
             @NonNull GnssNavigationMessage.Callback callback) {
-        return registerGnssNavigationMessageCallback(callback, null);
+        return registerGnssNavigationMessageCallback(Runnable::run, callback);
     }
 
     /**
@@ -2418,7 +2432,7 @@
             mAlarmManager = alarmManager;
             mAlarmManager.set(
                     ELAPSED_REALTIME,
-                    SystemClock.elapsedRealtime() + GET_CURRENT_LOCATION_TIMEOUT_MS,
+                    SystemClock.elapsedRealtime() + GET_CURRENT_LOCATION_MAX_TIMEOUT_MS,
                     "GetCurrentLocation",
                     this,
                     null);
@@ -2470,9 +2484,6 @@
         }
 
         @Override
-        public void onStatusChanged(String provider, int status, Bundle extras) {}
-
-        @Override
         public void onProviderEnabled(String provider) {}
 
         @Override
@@ -2482,6 +2493,11 @@
             deliverResult(null);
         }
 
+        @Override
+        public void onRemoved() {
+            deliverResult(null);
+        }
+
         private synchronized void deliverResult(@Nullable Location location) {
             if (mExecutor == null) {
                 return;
@@ -2557,37 +2573,6 @@
         }
 
         @Override
-        public void onStatusChanged(String provider, int status, Bundle extras) {
-            Executor currentExecutor = mExecutor;
-            if (currentExecutor == null) {
-                return;
-            }
-
-            try {
-                currentExecutor.execute(() -> {
-                    try {
-                        if (currentExecutor != mExecutor) {
-                            return;
-                        }
-
-                        // we may be under the binder identity if a direct executor is used
-                        long identity = Binder.clearCallingIdentity();
-                        try {
-                            mListener.onStatusChanged(provider, status, extras);
-                        } finally {
-                            Binder.restoreCallingIdentity(identity);
-                        }
-                    } finally {
-                        locationCallbackFinished();
-                    }
-                });
-            } catch (RejectedExecutionException e) {
-                locationCallbackFinished();
-                throw e;
-            }
-        }
-
-        @Override
         public void onProviderEnabled(String provider) {
             Executor currentExecutor = mExecutor;
             if (currentExecutor == null) {
@@ -2649,6 +2634,14 @@
             }
         }
 
+        @Override
+        public void onRemoved() {
+            unregister();
+            synchronized (mListeners) {
+                mListeners.remove(mListener, this);
+            }
+        }
+
         private void locationCallbackFinished() {
             try {
                 mService.locationCallbackFinished(this);
@@ -2690,9 +2683,9 @@
             return mTtff;
         }
 
-        public boolean addListener(@NonNull GpsStatus.Listener listener, @NonNull Handler handler)
+        public boolean addListener(@NonNull GpsStatus.Listener listener, @NonNull Executor executor)
                 throws RemoteException {
-            return addInternal(listener, handler);
+            return addInternal(listener, executor);
         }
 
         public boolean addListener(@NonNull OnNmeaMessageListener listener,
@@ -2746,9 +2739,14 @@
         protected boolean registerService() throws RemoteException {
             Preconditions.checkState(mListenerTransport == null);
 
-            mListenerTransport = new GnssStatusListener();
-            return mService.registerGnssStatusCallback(mListenerTransport,
-                    mContext.getPackageName());
+            GnssStatusListener transport = new GnssStatusListener();
+            if (mService.registerGnssStatusCallback(transport, mContext.getPackageName(),
+                    mContext.getFeatureId())) {
+                mListenerTransport = transport;
+                return true;
+            } else {
+                return false;
+            }
         }
 
         @Override
@@ -2806,9 +2804,14 @@
         protected boolean registerService() throws RemoteException {
             Preconditions.checkState(mListenerTransport == null);
 
-            mListenerTransport = new GnssMeasurementsListener();
-            return mService.addGnssMeasurementsListener(mListenerTransport,
-                    mContext.getPackageName(), "gnss measurement callback");
+            GnssMeasurementsListener transport = new GnssMeasurementsListener();
+            if (mService.addGnssMeasurementsListener(transport, mContext.getPackageName(),
+                    mContext.getFeatureId(), "gnss measurement callback")) {
+                mListenerTransport = transport;
+                return true;
+            } else {
+                return false;
+            }
         }
 
         @Override
@@ -2842,9 +2845,14 @@
         protected boolean registerService() throws RemoteException {
             Preconditions.checkState(mListenerTransport == null);
 
-            mListenerTransport = new GnssNavigationMessageListener();
-            return mService.addGnssNavigationMessageListener(mListenerTransport,
-                    mContext.getPackageName(), "gnss navigation callback");
+            GnssNavigationMessageListener transport = new GnssNavigationMessageListener();
+            if (mService.addGnssNavigationMessageListener(transport, mContext.getPackageName(),
+                    mContext.getFeatureId(), "gnss navigation callback")) {
+                mListenerTransport = transport;
+                return true;
+            } else {
+                return false;
+            }
         }
 
         @Override
@@ -2878,9 +2886,14 @@
         protected boolean registerService() throws RemoteException {
             Preconditions.checkState(mListenerTransport == null);
 
-            mListenerTransport = new BatchedLocationCallback();
-            return mService.addGnssBatchingCallback(mListenerTransport, mContext.getPackageName(),
-                     "batched location callback");
+            BatchedLocationCallback transport = new BatchedLocationCallback();
+            if (mService.addGnssBatchingCallback(transport, mContext.getPackageName(),
+                     mContext.getFeatureId(), "batched location callback")) {
+                mListenerTransport = transport;
+                return true;
+            } else {
+                return false;
+            }
         }
 
         @Override
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index 0902acf..3abd2c2 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -30,6 +30,8 @@
 import android.os.WorkSource;
 import android.util.TimeUtils;
 
+import com.android.internal.util.Preconditions;
+
 
 /**
  * A data object that contains quality of service parameters for requests
@@ -159,6 +161,7 @@
     private boolean mExplicitFastestInterval = false;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private long mExpireAt = Long.MAX_VALUE;  // no expiry
+    private long mExpireIn = Long.MAX_VALUE;  // no expiry
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private int mNumUpdates = Integer.MAX_VALUE;  // no expiry
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -195,6 +198,8 @@
     @NonNull
     public static LocationRequest createFromDeprecatedProvider(
             @NonNull String provider, long minTime, float minDistance, boolean singleShot) {
+        Preconditions.checkArgument(provider != null, "invalid null provider");
+
         if (minTime < 0) minTime = 0;
         if (minDistance < 0) minDistance = 0;
 
@@ -222,6 +227,8 @@
     @NonNull
     public static LocationRequest createFromDeprecatedCriteria(
             @NonNull Criteria criteria, long minTime, float minDistance, boolean singleShot) {
+        Preconditions.checkArgument(criteria != null, "invalid null criteria");
+
         if (minTime < 0) minTime = 0;
         if (minDistance < 0) minDistance = 0;
 
@@ -262,6 +269,7 @@
         mFastestInterval = src.mFastestInterval;
         mExplicitFastestInterval = src.mExplicitFastestInterval;
         mExpireAt = src.mExpireAt;
+        mExpireIn = src.mExpireIn;
         mNumUpdates = src.mNumUpdates;
         mSmallestDisplacement = src.mSmallestDisplacement;
         mProvider = src.mProvider;
@@ -336,7 +344,7 @@
      * @throws IllegalArgumentException if the interval is less than zero
      */
     public @NonNull LocationRequest setInterval(long millis) {
-        checkInterval(millis);
+        Preconditions.checkArgument(millis >= 0, "invalid interval: + millis");
         mInterval = millis;
         if (!mExplicitFastestInterval) {
             mFastestInterval = (long) (mInterval / FASTEST_INTERVAL_FACTOR);
@@ -364,9 +372,7 @@
      *
      * @param enabled Enable or disable low power mode
      * @return the same object, so that setters can be chained
-     * @hide
      */
-    @SystemApi
     public @NonNull LocationRequest setLowPowerMode(boolean enabled) {
         mLowPowerMode = enabled;
         return this;
@@ -374,10 +380,7 @@
 
     /**
      * Returns true if low power mode is enabled.
-     *
-     * @hide
      */
-    @SystemApi
     public boolean isLowPowerMode() {
         return mLowPowerMode;
     }
@@ -425,93 +428,80 @@
      * <p>An interval of 0 is allowed, but not recommended, since
      * location updates may be extremely fast on future implementations.
      *
-     * <p>If {@link #setFastestInterval} is set slower than {@link #setInterval},
+     * <p>If the fastest interval set is slower than {@link #setInterval},
      * then your effective fastest interval is {@link #setInterval}.
      *
-     * @param millis fastest interval for updates in milliseconds, exact
+     * @param millis fastest interval for updates in milliseconds
      * @return the same object, so that setters can be chained
      * @throws IllegalArgumentException if the interval is less than zero
      */
     public @NonNull LocationRequest setFastestInterval(long millis) {
-        checkInterval(millis);
+        Preconditions.checkArgument(millis >= 0, "invalid interval: + millis");
         mExplicitFastestInterval = true;
         mFastestInterval = millis;
         return this;
     }
 
     /**
-     * Get the fastest interval of this request, in milliseconds.
+     * Get the fastest interval of this request in milliseconds. The system will never provide
+     * location updates faster than the minimum of the fastest interval and {@link #getInterval}.
      *
-     * <p>The system will never provide location updates faster
-     * than the minimum of {@link #getFastestInterval} and
-     * {@link #getInterval}.
-     *
-     * @return fastest interval in milliseconds, exact
+     * @return fastest interval in milliseconds
      */
     public long getFastestInterval() {
         return mFastestInterval;
     }
 
     /**
-     * Set the duration of this request, in milliseconds.
+     * Set the expiration time of this request in milliseconds of realtime since boot. Values in the
+     * past are allowed, but indicate that the request has already expired. The location manager
+     * will automatically stop updates after the request expires.
      *
-     * <p>The duration begins immediately (and not when the request
-     * is passed to the location manager), so call this method again
-     * if the request is re-used at a later time.
+     * @param millis expiration time of request in milliseconds since boot
+     * @return the same object, so that setters can be chained
+     * @see SystemClock#elapsedRealtime()
+     * @deprecated Prefer {@link #setExpireIn(long)}.
+     */
+    @Deprecated
+    public @NonNull LocationRequest setExpireAt(long millis) {
+        mExpireAt = Math.max(millis, 0);
+        return this;
+    }
+
+    /**
+     * Get the request expiration time in milliseconds of realtime since boot.
      *
-     * <p>The location manager will automatically stop updates after
-     * the request expires.
-     *
-     * <p>The duration includes suspend time. Values less than 0
-     * are allowed, but indicate that the request has already expired.
+     * @return request expiration time in milliseconds since boot
+     * @see SystemClock#elapsedRealtime()
+     * @deprecated Prefer {@link #getExpireIn()}.
+     */
+    @Deprecated
+    public long getExpireAt() {
+        return mExpireAt;
+    }
+
+    /**
+     * Set the duration of this request in milliseconds of realtime. Values less than 0 are allowed,
+     * but indicate that the request has already expired. The location manager will automatically
+     * stop updates after the request expires.
      *
      * @param millis duration of request in milliseconds
      * @return the same object, so that setters can be chained
+     * @see SystemClock#elapsedRealtime()
      */
     public @NonNull LocationRequest setExpireIn(long millis) {
-        long elapsedRealtime = SystemClock.elapsedRealtime();
-
-        // Check for > Long.MAX_VALUE overflow (elapsedRealtime > 0):
-        if (millis > Long.MAX_VALUE - elapsedRealtime) {
-            mExpireAt = Long.MAX_VALUE;
-        } else {
-            mExpireAt = millis + elapsedRealtime;
-        }
-
-        if (mExpireAt < 0) mExpireAt = 0;
+        mExpireIn = millis;
         return this;
     }
 
     /**
-     * Set the request expiration time, in millisecond since boot.
+     * Get the request expiration duration in milliseconds of realtime.
      *
-     * <p>This expiration time uses the same time base as {@link SystemClock#elapsedRealtime}.
-     *
-     * <p>The location manager will automatically stop updates after
-     * the request expires.
-     *
-     * <p>The duration includes suspend time. Values before {@link SystemClock#elapsedRealtime}
-     * are allowed,  but indicate that the request has already expired.
-     *
-     * @param millis expiration time of request, in milliseconds since boot including suspend
-     * @return the same object, so that setters can be chained
+     * @return request expiration duration in milliseconds
+     * @see SystemClock#elapsedRealtime()
      */
-    public @NonNull LocationRequest setExpireAt(long millis) {
-        mExpireAt = millis;
-        if (mExpireAt < 0) mExpireAt = 0;
-        return this;
-    }
-
-    /**
-     * Get the request expiration time, in milliseconds since boot.
-     *
-     * <p>This value can be compared to {@link SystemClock#elapsedRealtime} to determine
-     * the time until expiration.
-     *
-     * @return expiration time of request, in milliseconds since boot including suspend
-     */
-    public long getExpireAt() {
-        return mExpireAt;
+    public long getExpireIn() {
+        return mExpireIn;
     }
 
     /**
@@ -632,13 +622,6 @@
     }
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    private static void checkInterval(long millis) {
-        if (millis < 0) {
-            throw new IllegalArgumentException("invalid interval: " + millis);
-        }
-    }
-
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private static void checkQuality(int quality) {
         switch (quality) {
             case ACCURACY_FINE:
@@ -676,6 +659,7 @@
                     request.setFastestInterval(in.readLong());
                     request.setInterval(in.readLong());
                     request.setExpireAt(in.readLong());
+                    request.setExpireIn(in.readLong());
                     request.setNumUpdates(in.readInt());
                     request.setSmallestDisplacement(in.readFloat());
                     request.setHideFromAppOps(in.readInt() != 0);
@@ -705,6 +689,7 @@
         parcel.writeLong(mFastestInterval);
         parcel.writeLong(mInterval);
         parcel.writeLong(mExpireAt);
+        parcel.writeLong(mExpireIn);
         parcel.writeInt(mNumUpdates);
         parcel.writeFloat(mSmallestDisplacement);
         parcel.writeInt(mHideFromAppOps ? 1 : 0);
@@ -747,9 +732,11 @@
         s.append(" fastest=");
         TimeUtils.formatDuration(mFastestInterval, s);
         if (mExpireAt != Long.MAX_VALUE) {
-            long expireIn = mExpireAt - SystemClock.elapsedRealtime();
+            s.append(" expireAt=").append(TimeUtils.formatUptime(mExpireAt));
+        }
+        if (mExpireIn != Long.MAX_VALUE) {
             s.append(" expireIn=");
-            TimeUtils.formatDuration(expireIn, s);
+            TimeUtils.formatDuration(mExpireIn, s);
         }
         if (mNumUpdates != Integer.MAX_VALUE) {
             s.append(" num=").append(mNumUpdates);
diff --git a/location/lib/Android.bp b/location/lib/Android.bp
index fe0f669..cd45e8e 100644
--- a/location/lib/Android.bp
+++ b/location/lib/Android.bp
@@ -17,10 +17,8 @@
 java_sdk_library {
     name: "com.android.location.provider",
     srcs: ["java/**/*.java"],
-    api_srcs: [":framework-all-sources"],
     libs: [
         "androidx.annotation_annotation",
-        "framework-all",
     ],
     api_packages: ["com.android.location.provider"],
 }
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index f797da7..9ad7f2a 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -908,6 +908,7 @@
 
     /** @hide */
     @UnsupportedAppUsage
+    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
     public void setMasterMute(boolean mute, int flags) {
         final IAudioService service = getService();
         try {
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 53bc65d..bb731a8 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -16,6 +16,7 @@
 
 package android.media;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
@@ -26,6 +27,8 @@
 import android.media.audiopolicy.AudioMix;
 import android.util.Log;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Map;
 
@@ -431,6 +434,50 @@
     public static final int DEAD_OBJECT        = -6;
     public static final int WOULD_BLOCK        = -7;
 
+    /** @hide */
+    @IntDef({
+            SUCCESS,
+            ERROR,
+            BAD_VALUE,
+            INVALID_OPERATION,
+            PERMISSION_DENIED,
+            NO_INIT,
+            DEAD_OBJECT,
+            WOULD_BLOCK
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AudioSystemError {}
+
+    /**
+     * Convert an int error value to its String value for readability.
+     * Accepted error values are the java AudioSystem errors, matching android_media_AudioErrors.h,
+     * which map onto the native status_t type.
+     * @param error one of the java AudioSystem errors
+     * @return a human-readable string
+     */
+    public static String audioSystemErrorToString(@AudioSystemError int error) {
+        switch(error) {
+            case SUCCESS:
+                return "SUCCESS";
+            case ERROR:
+                return "ERROR";
+            case BAD_VALUE:
+                return "BAD_VALUE";
+            case INVALID_OPERATION:
+                return "INVALID_OPERATION";
+            case PERMISSION_DENIED:
+                return "PERMISSION_DENIED";
+            case NO_INIT:
+                return "NO_INIT";
+            case DEAD_OBJECT:
+                return "DEAD_OBJECT";
+            case WOULD_BLOCK:
+                return "WOULD_BLOCK";
+            default:
+                return ("unknown error:" + error);
+        }
+    }
+
     /*
      * AudioPolicyService methods
      */
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 33ddfa7..d6a4ea7 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -39,6 +39,7 @@
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.DataInput;
 import java.io.DataInputStream;
 import java.io.EOFException;
@@ -68,6 +69,7 @@
 import java.util.TimeZone;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.zip.CRC32;
 
 /**
  * This is a class for reading and writing Exif tags in a JPEG file or a RAW image file.
@@ -502,11 +504,22 @@
     // 3.7. eXIf Exchangeable Image File (Exif) Profile
     private static final byte[] PNG_CHUNK_TYPE_EXIF = new byte[]{(byte) 0x65, (byte) 0x58,
             (byte) 0x49, (byte) 0x66};
+    private static final byte[] PNG_CHUNK_TYPE_IHDR = new byte[]{(byte) 0x49, (byte) 0x48,
+            (byte) 0x44, (byte) 0x52};
     private static final byte[] PNG_CHUNK_TYPE_IEND = new byte[]{(byte) 0x49, (byte) 0x45,
             (byte) 0x4e, (byte) 0x44};
-    private static final int PNG_CHUNK_LENGTH_BYTE_LENGTH = 4;
+    private static final int PNG_CHUNK_TYPE_BYTE_LENGTH = 4;
     private static final int PNG_CHUNK_CRC_BYTE_LENGTH = 4;
 
+    // See https://developers.google.com/speed/webp/docs/riff_container, Section "WebP File Header"
+    private static final byte[] WEBP_SIGNATURE_1 = new byte[] {'R', 'I', 'F', 'F'};
+    private static final byte[] WEBP_SIGNATURE_2 = new byte[] {'W', 'E', 'B', 'P'};
+    private static final int WEBP_FILE_SIZE_BYTE_LENGTH = 4;
+    private static final byte[] WEBP_CHUNK_TYPE_EXIF = new byte[]{(byte) 0x45, (byte) 0x58,
+            (byte) 0x49, (byte) 0x46};
+    private static final int WEBP_CHUNK_TYPE_BYTE_LENGTH = 4;
+    private static final int WEBP_CHUNK_SIZE_BYTE_LENGTH = 4;
+
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private static SimpleDateFormat sFormatter;
     private static SimpleDateFormat sFormatterTz;
@@ -1325,6 +1338,7 @@
     private static final int IMAGE_TYPE_SRW = 11;
     private static final int IMAGE_TYPE_HEIF = 12;
     private static final int IMAGE_TYPE_PNG = 13;
+    private static final int IMAGE_TYPE_WEBP = 14;
 
     static {
         sFormatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
@@ -1869,6 +1883,10 @@
                         getPngAttributes(inputStream);
                         break;
                     }
+                    case IMAGE_TYPE_WEBP: {
+                        getWebpAttributes(inputStream);
+                        break;
+                    }
                     case IMAGE_TYPE_ARW:
                     case IMAGE_TYPE_CR2:
                     case IMAGE_TYPE_DNG:
@@ -1934,7 +1952,7 @@
      * {@link #setAttribute(String,String)} to set all attributes to write and
      * make a single call rather than multiple calls for each attribute.
      * <p>
-     * This method is only supported for JPEG files.
+     * This method is only supported for JPEG and PNG files.
      * <p class="note">
      * Note: after calling this method, any attempts to obtain range information
      * from {@link #getAttributeRange(String)} or {@link #getThumbnailRange()}
@@ -1943,8 +1961,9 @@
      * </p>
      */
     public void saveAttributes() throws IOException {
-        if (!mIsSupportedFile || mMimeType != IMAGE_TYPE_JPEG) {
-            throw new IOException("ExifInterface only supports saving attributes on JPEG formats.");
+        if (!mIsSupportedFile || (mMimeType != IMAGE_TYPE_JPEG && mMimeType != IMAGE_TYPE_PNG)) {
+            throw new IOException("ExifInterface only supports saving attributes on JPEG or PNG "
+                    + "formats.");
         }
         if (mIsInputStream || (mSeekableFileDescriptor == null && mFilename == null)) {
             throw new IOException(
@@ -1973,7 +1992,11 @@
                     throw new IOException("Couldn't rename to " + tempFile.getAbsolutePath());
                 }
             } else if (mSeekableFileDescriptor != null) {
-                tempFile = File.createTempFile("temp", "jpg");
+                if (mMimeType == IMAGE_TYPE_JPEG) {
+                    tempFile = File.createTempFile("temp", "jpg");
+                } else if (mMimeType == IMAGE_TYPE_PNG) {
+                    tempFile = File.createTempFile("temp", "png");
+                }
                 Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET);
                 in = new FileInputStream(mSeekableFileDescriptor);
                 out = new FileOutputStream(tempFile);
@@ -1999,7 +2022,11 @@
             }
             try (BufferedInputStream bufferedIn = new BufferedInputStream(in);
                  BufferedOutputStream bufferedOut = new BufferedOutputStream(out)) {
-                saveJpegAttributes(bufferedIn, bufferedOut);
+                if (mMimeType == IMAGE_TYPE_JPEG) {
+                    saveJpegAttributes(bufferedIn, bufferedOut);
+                } else if (mMimeType == IMAGE_TYPE_PNG) {
+                    savePngAttributes(bufferedIn, bufferedOut);
+                }
             }
         } catch (Exception e) {
             if (mFilename != null) {
@@ -2431,6 +2458,8 @@
             return IMAGE_TYPE_RW2;
         } else if (isPngFormat(signatureCheckBytes)) {
             return IMAGE_TYPE_PNG;
+        } else if (isWebpFormat(signatureCheckBytes)) {
+            return IMAGE_TYPE_WEBP;
         }
         // Certain file formats (PEF) are identified in readImageFileDirectory()
         return IMAGE_TYPE_UNKNOWN;
@@ -2609,6 +2638,26 @@
         return true;
     }
 
+    /**
+     * WebP's file signature is composed of 12 bytes:
+     *   'RIFF' (4 bytes) + file length value (4 bytes) + 'WEBP' (4 bytes)
+     * See https://developers.google.com/speed/webp/docs/riff_container, Section "WebP File Header"
+     */
+    private boolean isWebpFormat(byte[] signatureCheckBytes) throws IOException {
+        for (int i = 0; i < WEBP_SIGNATURE_1.length; i++) {
+            if (signatureCheckBytes[i] != WEBP_SIGNATURE_1[i]) {
+                return false;
+            }
+        }
+        for (int i = 0; i < WEBP_SIGNATURE_2.length; i++) {
+            if (signatureCheckBytes[i + WEBP_SIGNATURE_1.length + WEBP_FILE_SIZE_BYTE_LENGTH]
+                    != WEBP_SIGNATURE_2[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     private static boolean isStandalone(InputStream inputStream) throws IOException {
         byte[] signatureCheckBytes = new byte[IDENTIFIER_EXIF_APP1.length];
         inputStream.read(signatureCheckBytes);
@@ -3146,30 +3195,36 @@
         int bytesRead = 0;
 
         // Skip the signature bytes
-        in.seek(PNG_SIGNATURE.length);
+        in.skipBytes(PNG_SIGNATURE.length);
         bytesRead += PNG_SIGNATURE.length;
 
+        // Each chunk is made up of four parts:
+        //   1) Length: 4-byte unsigned integer indicating the number of bytes in the
+        //   Chunk Data field. Excludes Chunk Type and CRC bytes.
+        //   2) Chunk Type: 4-byte chunk type code.
+        //   3) Chunk Data: The data bytes. Can be zero-length.
+        //   4) CRC: 4-byte data calculated on the preceding bytes in the chunk. Always
+        //   present.
+        // --> 4 (length bytes) + 4 (type bytes) + X (data bytes) + 4 (CRC bytes)
+        // See PNG (Portable Network Graphics) Specification, Version 1.2,
+        // 3.2. Chunk layout
         try {
             while (true) {
-                // Each chunk is made up of four parts:
-                //   1) Length: 4-byte unsigned integer indicating the number of bytes in the
-                //   Chunk Data field. Excludes Chunk Type and CRC bytes.
-                //   2) Chunk Type: 4-byte chunk type code.
-                //   3) Chunk Data: The data bytes. Can be zero-length.
-                //   4) CRC: 4-byte data calculated on the preceding bytes in the chunk. Always
-                //   present.
-                // --> 4 (length bytes) + 4 (type bytes) + X (data bytes) + 4 (CRC bytes)
-                // See PNG (Portable Network Graphics) Specification, Version 1.2,
-                // 3.2. Chunk layout
                 int length = in.readInt();
                 bytesRead += 4;
 
-                byte[] type = new byte[PNG_CHUNK_LENGTH_BYTE_LENGTH];
+                byte[] type = new byte[PNG_CHUNK_TYPE_BYTE_LENGTH];
                 if (in.read(type) != type.length) {
                     throw new IOException("Encountered invalid length while parsing PNG chunk"
                             + "type");
                 }
-                bytesRead += PNG_CHUNK_LENGTH_BYTE_LENGTH;
+                bytesRead += PNG_CHUNK_TYPE_BYTE_LENGTH;
+
+                // The first chunk must be the IHDR chunk
+                if (bytesRead == 16 && !Arrays.equals(type, PNG_CHUNK_TYPE_IHDR)) {
+                    throw new IOException("Encountered invalid PNG file--IHDR chunk should appear"
+                            + "as the first chunk");
+                }
 
                 if (Arrays.equals(type, PNG_CHUNK_TYPE_IEND)) {
                     // IEND marks the end of the image.
@@ -3181,9 +3236,25 @@
                         throw new IOException("Failed to read given length for given PNG chunk "
                                 + "type: " + byteArrayToHexString(type));
                     }
+
+                    // Compare CRC values for potential data corruption.
+                    int dataCrcValue = in.readInt();
+                    // Cyclic Redundancy Code used to check for corruption of the data
+                    CRC32 crc = new CRC32();
+                    crc.update(type);
+                    crc.update(data);
+                    if ((int) crc.getValue() != dataCrcValue) {
+                        throw new IOException("Encountered invalid CRC value for PNG-EXIF chunk."
+                                + "\n recorded CRC value: " + dataCrcValue + ", calculated CRC "
+                                + "value: " + crc.getValue());
+                    }
+
                     readExifSegment(data, IFD_TYPE_PRIMARY);
 
                     validateImages();
+
+                    // Save offset values for handleThumbnailFromJfif() function
+                    mExifOffset = bytesRead;
                     break;
                 } else {
                     // Skip to next chunk
@@ -3191,8 +3262,6 @@
                     bytesRead += length + PNG_CHUNK_CRC_BYTE_LENGTH;
                 }
             }
-            // Save offset values for handleThumbnailFromJfif() function
-            mExifOffset = bytesRead;
         } catch (EOFException e) {
             // Should not reach here. Will only reach here if the file is corrupted or
             // does not follow the PNG specifications
@@ -3200,6 +3269,75 @@
         }
     }
 
+    // WebP contains EXIF data as a RIFF File Format Chunk
+    // All references below can be found in the following link.
+    // https://developers.google.com/speed/webp/docs/riff_container
+    private void getWebpAttributes(ByteOrderedDataInputStream in) throws IOException {
+        if (DEBUG) {
+            Log.d(TAG, "getWebpAttributes starting with: " + in);
+        }
+        // WebP uses little-endian by default.
+        // See Section "Terminology & Basics"
+        in.setByteOrder(ByteOrder.LITTLE_ENDIAN);
+        in.skipBytes(WEBP_SIGNATURE_1.length);
+        // File size corresponds to the size of the entire file from offset 8.
+        // See Section "WebP File Header"
+        int fileSize = in.readInt() + 8;
+        int bytesRead = 8;
+        bytesRead += in.skipBytes(WEBP_SIGNATURE_2.length);
+        try {
+            while (true) {
+                // Each chunk is made up of three parts:
+                //   1) Chunk FourCC: 4-byte concatenating four ASCII characters.
+                //   2) Chunk Size: 4-byte unsigned integer indicating the size of the chunk.
+                //                  Excludes Chunk FourCC and Chunk Size bytes.
+                //   3) Chunk Payload: data payload. A single padding byte ('0') is added if
+                //                     Chunk Size is odd.
+                // See Section "RIFF File Format"
+                byte[] code = new byte[WEBP_CHUNK_TYPE_BYTE_LENGTH];
+                if (in.read(code) != code.length) {
+                    throw new IOException("Encountered invalid length while parsing WebP chunk"
+                            + "type");
+                }
+                bytesRead += 4;
+                int chunkSize = in.readInt();
+                bytesRead += 4;
+                if (Arrays.equals(WEBP_CHUNK_TYPE_EXIF, code)) {
+                    // TODO: Need to handle potential OutOfMemoryError
+                    byte[] payload = new byte[chunkSize];
+                    if (in.read(payload) != chunkSize) {
+                        throw new IOException("Failed to read given length for given PNG chunk "
+                                + "type: " + byteArrayToHexString(code));
+                    }
+                    readExifSegment(payload, IFD_TYPE_PRIMARY);
+                    break;
+                } else {
+                    // Add a single padding byte at end if chunk size is odd
+                    chunkSize = (chunkSize % 2 == 1) ? chunkSize + 1 : chunkSize;
+                    // Check if skipping to next chunk is necessary
+                    if (bytesRead + chunkSize == fileSize) {
+                        // Reached end of file
+                        break;
+                    } else if (bytesRead + chunkSize > fileSize) {
+                        throw new IOException("Encountered WebP file with invalid chunk size");
+                    }
+                    // Skip to next chunk
+                    int skipped = in.skipBytes(chunkSize);
+                    if (skipped != chunkSize) {
+                        throw new IOException("Encountered WebP file with invalid chunk size");
+                    }
+                    bytesRead += skipped;
+                }
+            }
+            // Save offset values for handleThumbnailFromJfif() function
+            mExifOffset = bytesRead;
+        } catch (EOFException e) {
+            // Should not reach here. Will only reach here if the file is corrupted or
+            // does not follow the WebP specifications
+            throw new IOException("Encountered corrupt WebP file.");
+        }
+    }
+
     // Stores a new JPEG image with EXIF attributes into a given output stream.
     private void saveJpegAttributes(InputStream inputStream, OutputStream outputStream)
             throws IOException {
@@ -3298,6 +3436,62 @@
         }
     }
 
+    private void savePngAttributes(InputStream inputStream, OutputStream outputStream)
+            throws IOException {
+        if (DEBUG) {
+            Log.d(TAG, "savePngAttributes starting with (inputStream: " + inputStream
+                    + ", outputStream: " + outputStream + ")");
+        }
+        DataInputStream dataInputStream = new DataInputStream(inputStream);
+        ByteOrderedDataOutputStream dataOutputStream =
+                new ByteOrderedDataOutputStream(outputStream, ByteOrder.BIG_ENDIAN);
+        // Copy PNG signature bytes
+        copy(dataInputStream, dataOutputStream, PNG_SIGNATURE.length);
+        // EXIF chunk can appear anywhere between the first (IHDR) and last (IEND) chunks, except
+        // between IDAT chunks.
+        // Adhering to these rules,
+        //   1) if EXIF chunk did not exist in the original file, it will be stored right after the
+        //      first chunk,
+        //   2) if EXIF chunk existed in the original file, it will be stored in the same location.
+        if (mExifOffset == 0) {
+            // Copy IHDR chunk bytes
+            int ihdrChunkLength = dataInputStream.readInt();
+            dataOutputStream.writeInt(ihdrChunkLength);
+            copy(dataInputStream, dataOutputStream, PNG_CHUNK_TYPE_BYTE_LENGTH
+                    + ihdrChunkLength + PNG_CHUNK_CRC_BYTE_LENGTH);
+        } else {
+            // Copy up until the point where EXIF chunk length information is stored.
+            int copyLength = mExifOffset - PNG_SIGNATURE.length
+                    - 4 /* PNG EXIF chunk length bytes */
+                    - PNG_CHUNK_TYPE_BYTE_LENGTH;
+            copy(dataInputStream, dataOutputStream, copyLength);
+            // Skip to the start of the chunk after the EXIF chunk
+            int exifChunkLength = dataInputStream.readInt();
+            dataInputStream.skipBytes(PNG_CHUNK_TYPE_BYTE_LENGTH + exifChunkLength
+                    + PNG_CHUNK_CRC_BYTE_LENGTH);
+        }
+        // Write EXIF data
+        try (ByteArrayOutputStream exifByteArrayOutputStream = new ByteArrayOutputStream()) {
+            // A byte array is needed to calculate the CRC value of this chunk which requires
+            // the chunk type bytes and the chunk data bytes.
+            ByteOrderedDataOutputStream exifDataOutputStream =
+                    new ByteOrderedDataOutputStream(exifByteArrayOutputStream,
+                            ByteOrder.BIG_ENDIAN);
+            // Store Exif data in separate byte array
+            writeExifSegment(exifDataOutputStream, 0);
+            byte[] exifBytes =
+                    ((ByteArrayOutputStream) exifDataOutputStream.mOutputStream).toByteArray();
+            // Write EXIF chunk data
+            dataOutputStream.write(exifBytes);
+            // Write EXIF chunk CRC
+            CRC32 crc = new CRC32();
+            crc.update(exifBytes, 4 /* skip length bytes */, exifBytes.length - 4);
+            dataOutputStream.writeInt((int) crc.getValue());
+        }
+        // Copy the rest of the file
+        Streams.copy(dataInputStream, dataOutputStream);
+    }
+
     // Reads the given EXIF byte area and save its tag data into attributes.
     private void readExifSegment(byte[] exifBytes, int imageType) throws IOException {
         ByteOrderedDataInputStream dataInputStream =
@@ -3684,12 +3878,18 @@
             int thumbnailOffset = jpegInterchangeFormatAttribute.getIntValue(mExifByteOrder);
             int thumbnailLength = jpegInterchangeFormatLengthAttribute.getIntValue(mExifByteOrder);
 
-            if (mMimeType == IMAGE_TYPE_JPEG || mMimeType == IMAGE_TYPE_RAF
-                    || mMimeType == IMAGE_TYPE_RW2 || mMimeType == IMAGE_TYPE_PNG) {
-                thumbnailOffset += mExifOffset;
-            } else if (mMimeType == IMAGE_TYPE_ORF) {
-                // Update offset value since RAF files have IFD data preceding MakerNote data.
-                thumbnailOffset += mOrfMakerNoteOffset;
+            switch (mMimeType) {
+                case IMAGE_TYPE_JPEG:
+                case IMAGE_TYPE_RAF:
+                case IMAGE_TYPE_RW2:
+                case IMAGE_TYPE_PNG:
+                case IMAGE_TYPE_WEBP:
+                    thumbnailOffset += mExifOffset;
+                    break;
+                case IMAGE_TYPE_ORF:
+                    // Update offset value since RAF files have IFD data preceding MakerNote data.
+                    thumbnailOffset += mOrfMakerNoteOffset;
+                    break;
             }
             // The following code limits the size of thumbnail size not to overflow EXIF data area.
             thumbnailLength = Math.min(thumbnailLength, in.getLength() - thumbnailOffset);
@@ -3991,7 +4191,7 @@
         }
 
         // Calculate IFD offsets.
-        int position = 8;
+        int position = 8; // 8 bytes are for TIFF headers
         for (int ifdType = 0; ifdType < EXIF_TAGS.length; ++ifdType) {
             if (!mAttributes[ifdType].isEmpty()) {
                 ifdOffsets[ifdType] = position;
@@ -4006,13 +4206,16 @@
             position += mThumbnailLength;
         }
 
-        // Calculate the total size
-        int totalSize = position + 8;  // eight bytes is for header part.
+        int totalSize = position;
+        if (mMimeType == IMAGE_TYPE_JPEG) {
+            // Add 8 bytes for APP1 size and identifier data
+            totalSize += 8;
+        }
         if (DEBUG) {
-            Log.d(TAG, "totalSize length: " + totalSize);
             for (int i = 0; i < EXIF_TAGS.length; ++i) {
-                Log.d(TAG, String.format("index: %d, offsets: %d, tag count: %d, data sizes: %d",
-                        i, ifdOffsets[i], mAttributes[i].size(), ifdDataSizes[i]));
+                Log.d(TAG, String.format("index: %d, offsets: %d, tag count: %d, data sizes: %d, "
+                                + "total size: %d", i, ifdOffsets[i], mAttributes[i].size(),
+                        ifdDataSizes[i], totalSize));
             }
         }
 
@@ -4030,9 +4233,17 @@
                     ifdOffsets[IFD_TYPE_INTEROPERABILITY], mExifByteOrder));
         }
 
+        if (mMimeType == IMAGE_TYPE_JPEG) {
+            // Write JPEG specific data (APP1 size, APP1 identifier)
+            dataOutputStream.writeUnsignedShort(totalSize);
+            dataOutputStream.write(IDENTIFIER_EXIF_APP1);
+        } else if (mMimeType == IMAGE_TYPE_PNG) {
+            // Write PNG specific data (chunk size, chunk type)
+            dataOutputStream.writeInt(totalSize);
+            dataOutputStream.write(PNG_CHUNK_TYPE_EXIF);
+        }
+
         // Write TIFF Headers. See JEITA CP-3451C Section 4.5.2. Table 1.
-        dataOutputStream.writeUnsignedShort(totalSize);
-        dataOutputStream.write(IDENTIFIER_EXIF_APP1);
         dataOutputStream.writeShort(mExifByteOrder == ByteOrder.BIG_ENDIAN
                 ? BYTE_ALIGN_MM : BYTE_ALIGN_II);
         dataOutputStream.setByteOrder(mExifByteOrder);
@@ -4108,7 +4319,7 @@
      * Determines the data format of EXIF entry value.
      *
      * @param entryValue The value to be determined.
-     * @return Returns two data formats gussed as a pair in integer. If there is no two candidate
+     * @return Returns two data formats guessed as a pair in integer. If there is no two candidate
                data formats for the given entry value, returns {@code -1} in the second of the pair.
      */
     private static Pair<Integer, Integer> guessDataFormat(String entryValue) {
@@ -4430,7 +4641,7 @@
     // An output stream to write EXIF data area, which can be written in either little or big endian
     // order.
     private static class ByteOrderedDataOutputStream extends FilterOutputStream {
-        private final OutputStream mOutputStream;
+        final OutputStream mOutputStream;
         private ByteOrder mByteOrder;
 
         public ByteOrderedDataOutputStream(OutputStream out, ByteOrder byteOrder) {
@@ -4546,6 +4757,25 @@
     }
 
     /**
+     * Copies the given number of the bytes from {@code in} to {@code out}. Neither stream is
+     * closed.
+     */
+    private static void copy(InputStream in, OutputStream out, int numBytes) throws IOException {
+        int remainder = numBytes;
+        byte[] buffer = new byte[8192];
+        while (remainder > 0) {
+            int bytesToRead = Math.min(remainder, 8192);
+            int bytesRead = in.read(buffer, 0, bytesToRead);
+            if (bytesRead != bytesToRead) {
+                throw new IOException("Failed to copy the given amount of bytes from the input"
+                        + "stream to the output stream.");
+            }
+            remainder -= bytesRead;
+            out.write(buffer, 0, bytesRead);
+        }
+    }
+
+    /**
      * Convert given int[] to long[]. If long[] is given, just return it.
      * Return null for other types of input.
      */
diff --git a/media/java/android/media/IMediaRouter2Client.aidl b/media/java/android/media/IMediaRouter2Client.aidl
index 26184af..72c33f99 100644
--- a/media/java/android/media/IMediaRouter2Client.aidl
+++ b/media/java/android/media/IMediaRouter2Client.aidl
@@ -16,12 +16,14 @@
 
 package android.media;
 
-import android.media.MediaRoute2ProviderInfo;
+import android.media.MediaRoute2Info;
 
 /**
  * @hide
  */
 oneway interface IMediaRouter2Client {
     void notifyRestoreRoute();
-    void notifyProviderInfosUpdated(in List<MediaRoute2ProviderInfo> providers);
+    void notifyRoutesAdded(in List<MediaRoute2Info> routes);
+    void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
+    void notifyRoutesChanged(in List<MediaRoute2Info> routes);
 }
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index f813d1b..7bc2b31 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -192,13 +192,15 @@
 
         mMaxImages = maxImages;
 
-        if (format == ImageFormat.UNKNOWN) {
-            format = SurfaceUtils.getSurfaceFormat(surface);
-        }
         // Note that the underlying BufferQueue is working in synchronous mode
         // to avoid dropping any buffers.
         mNativeContext = nativeInit(new WeakReference<>(this), surface, maxImages, format);
 
+        // nativeInit internally overrides UNKNOWN format. So does surface format query after
+        // nativeInit and before getEstimatedNativeAllocBytes().
+        if (format == ImageFormat.UNKNOWN) {
+            format = SurfaceUtils.getSurfaceFormat(surface);
+        }
         // Estimate the native buffer allocation size and register it so it gets accounted for
         // during GC. Note that this doesn't include the buffers required by the buffer queue
         // itself and the buffers requested by the producer.
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index cc5ddeb..5d2bdd7 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -34,6 +34,7 @@
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -62,7 +63,8 @@
      * method before the rest of the methods in this class. This method may be
      * time-consuming.
      *
-     * @param path The path of the input media file.
+     * @param path The path, or the URI (doesn't support streaming source currently)
+     * of the input media file.
      * @throws IllegalArgumentException If the path is invalid.
      */
     public void setDataSource(String path) throws IllegalArgumentException {
@@ -70,6 +72,15 @@
             throw new IllegalArgumentException("null path");
         }
 
+        final Uri uri = Uri.parse(path);
+        final String scheme = uri.getScheme();
+        if ("file".equals(scheme)) {
+            path = uri.getPath();
+        } else if (scheme != null) {
+            setDataSource(path, new HashMap<String, String>());
+            return;
+        }
+
         try (FileInputStream is = new FileInputStream(path)) {
             FileDescriptor fd = is.getFD();
             setDataSource(fd, 0, 0x7ffffffffffffffL);
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 7906fa3..7d107dd 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -89,6 +89,10 @@
  * of audio/video files and streams. An example on how to use the methods in
  * this class can be found in {@link android.widget.VideoView}.
  *
+ * <p>MediaPlayer is not thread-safe. Creation of and all access to player instances
+ * should be on the same thread. If registering <a href="#Callbacks">callbacks</a>,
+ * the thread must have a Looper.
+ *
  * <p>Topics covered here are:
  * <ol>
  * <li><a href="#StateDiagram">State Diagram</a>
@@ -305,7 +309,7 @@
  *         </li>
  *     <li>When the playback reaches the end of stream, the playback completes.
  *         <ul>
- *         <li>If the looping mode was being set to <var>true</var>with
+ *         <li>If the looping mode was being set to <var>true</var> with
  *         {@link #setLooping(boolean)}, the MediaPlayer object shall remain in
  *         the <em>Started</em> state.</li>
  *         <li>If the looping mode was set to <var>false
@@ -554,13 +558,13 @@
  * possible runtime errors during playback or streaming. Registration for
  * these events is done by properly setting the appropriate listeners (via calls
  * to
- * {@link #setOnPreparedListener(OnPreparedListener)}setOnPreparedListener,
- * {@link #setOnVideoSizeChangedListener(OnVideoSizeChangedListener)}setOnVideoSizeChangedListener,
- * {@link #setOnSeekCompleteListener(OnSeekCompleteListener)}setOnSeekCompleteListener,
- * {@link #setOnCompletionListener(OnCompletionListener)}setOnCompletionListener,
- * {@link #setOnBufferingUpdateListener(OnBufferingUpdateListener)}setOnBufferingUpdateListener,
- * {@link #setOnInfoListener(OnInfoListener)}setOnInfoListener,
- * {@link #setOnErrorListener(OnErrorListener)}setOnErrorListener, etc).
+ * {@link #setOnPreparedListener(OnPreparedListener) setOnPreparedListener},
+ * {@link #setOnVideoSizeChangedListener(OnVideoSizeChangedListener) setOnVideoSizeChangedListener},
+ * {@link #setOnSeekCompleteListener(OnSeekCompleteListener) setOnSeekCompleteListener},
+ * {@link #setOnCompletionListener(OnCompletionListener) setOnCompletionListener},
+ * {@link #setOnBufferingUpdateListener(OnBufferingUpdateListener) setOnBufferingUpdateListener},
+ * {@link #setOnInfoListener(OnInfoListener) setOnInfoListener},
+ * {@link #setOnErrorListener(OnErrorListener) setOnErrorListener}, etc).
  * In order to receive the respective callback
  * associated with these listeners, applications are required to create
  * MediaPlayer objects on a thread with its own Looper running (main UI
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index bf7da23..9723652 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -337,9 +337,14 @@
 
         /**
          * Audio source for capturing broadcast radio tuner output.
+         * Capturing the radio tuner output requires the
+         * {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT} permission.
+         * This permission is reserved for use by system components and is not available to
+         * third-party applications.
          * @hide
          */
         @SystemApi
+        @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT)
         public static final int RADIO_TUNER = 1998;
 
         /**
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index 59bd96f..457ccb7 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -314,7 +314,7 @@
         List<String> mSupportedCategories;
         int mVolume;
         int mVolumeMax;
-        int mVolumeHandling;
+        int mVolumeHandling = PLAYBACK_VOLUME_FIXED;
         Bundle mExtras;
 
         public Builder(@NonNull String id, @NonNull String name) {
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index b52e2d6..ce18ab3 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -33,7 +33,9 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.Executor;
@@ -51,23 +53,23 @@
     @GuardedBy("sLock")
     private static MediaRouter2 sInstance;
 
-    private Context mContext;
+    private final Context mContext;
     private final IMediaRouterService mMediaRouterService;
 
     private final CopyOnWriteArrayList<CallbackRecord> mCallbackRecords =
             new CopyOnWriteArrayList<>();
-    @GuardedBy("sLock")
-    private List<String> mControlCategories = Collections.emptyList();
+
+    private final String mPackageName;
+    private final Map<String, MediaRoute2Info> mRoutes = new HashMap<>();
+
+    private volatile List<String> mControlCategories = Collections.emptyList();
+
+    private MediaRoute2Info mSelectedRoute;
     @GuardedBy("sLock")
     private Client mClient;
 
-    private final String mPackageName;
     final Handler mHandler;
-
-    List<MediaRoute2ProviderInfo> mProviders = Collections.emptyList();
-    volatile List<MediaRoute2Info> mRoutes = Collections.emptyList();
-
-    MediaRoute2Info mSelectedRoute;
+    volatile List<MediaRoute2Info> mFilteredRoutes = Collections.emptyList();
 
     /**
      * Gets an instance of the media router associated with the context.
@@ -137,6 +139,7 @@
                 }
             }
         }
+        //TODO: Is it thread-safe?
         record.notifyRoutes();
 
         //TODO: Update discovery request here.
@@ -181,31 +184,22 @@
     public void setControlCategories(@NonNull Collection<String> controlCategories) {
         Objects.requireNonNull(controlCategories, "control categories must not be null");
 
-        Client client;
-        List<String> newControlCategories = new ArrayList<>(controlCategories);
-        synchronized (sLock) {
-            mControlCategories = newControlCategories;
-            client = mClient;
-        }
-        if (client != null) {
-            try {
-                mMediaRouterService.setControlCategories2(client, newControlCategories);
-            } catch (RemoteException ex) {
-                Log.e(TAG, "Unable to set control categories.", ex);
-            }
-        }
-        mHandler.sendMessage(obtainMessage(MediaRouter2::refreshAndNotifyRoutes, this));
+        // To ensure invoking callbacks correctly according to control categories
+        mHandler.sendMessage(obtainMessage(MediaRouter2::setControlCategoriesOnHandler,
+                MediaRouter2.this, new ArrayList<>(controlCategories)));
     }
 
+
     /**
-     * Gets the list of {@link MediaRoute2Info routes} currently known to the media router.
+     * Gets the unmodifiable list of {@link MediaRoute2Info routes} currently
+     * known to the media router.
      *
      * @return the list of routes that support at least one of the control categories set by
      * the application
      */
     @NonNull
     public List<MediaRoute2Info> getRoutes() {
-        return mRoutes;
+        return mFilteredRoutes;
     }
 
     /**
@@ -326,102 +320,145 @@
         return -1;
     }
 
-    void onProviderInfosUpdated(List<MediaRoute2ProviderInfo> providers) {
-        if (providers == null) {
-            Log.w(TAG, "Providers info is null.");
-            return;
-        }
+    private void setControlCategoriesOnHandler(List<String> newControlCategories) {
+        List<String> prevControlCategories = mControlCategories;
+        List<MediaRoute2Info> addedRoutes = new ArrayList<>();
+        List<MediaRoute2Info> removedRoutes = new ArrayList<>();
+        List<MediaRoute2Info> filteredRoutes = new ArrayList<>();
 
-        mProviders = providers;
-        refreshAndNotifyRoutes();
-    }
-
-    void refreshAndNotifyRoutes() {
-        ArrayList<MediaRoute2Info> routes = new ArrayList<>();
-
-        List<String> controlCategories;
+        mControlCategories = newControlCategories;
+        Client client;
         synchronized (sLock) {
-            controlCategories = mControlCategories;
+            client = mClient;
+        }
+        if (client != null) {
+            try {
+                mMediaRouterService.setControlCategories2(client, mControlCategories);
+            } catch (RemoteException ex) {
+                Log.e(TAG, "Unable to set control categories.", ex);
+            }
         }
 
-        for (MediaRoute2ProviderInfo provider : mProviders) {
-            updateProvider(provider, controlCategories, routes);
+        for (MediaRoute2Info route : mRoutes.values()) {
+            boolean preSupported = route.supportsControlCategory(prevControlCategories);
+            boolean postSupported = route.supportsControlCategory(newControlCategories);
+            if (postSupported) {
+                filteredRoutes.add(route);
+            }
+            if (preSupported == postSupported) {
+                continue;
+            }
+            if (preSupported) {
+                removedRoutes.add(route);
+            } else {
+                addedRoutes.add(route);
+            }
         }
+        mFilteredRoutes = Collections.unmodifiableList(filteredRoutes);
 
-        //TODO: Can orders be changed?
-        if (!Objects.equals(mRoutes, routes)) {
-            mRoutes = Collections.unmodifiableList(routes);
-            notifyRouteListChanged(mRoutes);
+        if (removedRoutes.size() > 0) {
+            notifyRoutesRemoved(removedRoutes);
+        }
+        if (addedRoutes.size() > 0) {
+            notifyRoutesAdded(addedRoutes);
         }
     }
 
-    void updateProvider(MediaRoute2ProviderInfo provider, List<String> controlCategories,
-            List<MediaRoute2Info> outRoutes) {
-        if (provider == null || !provider.isValid()) {
-            Log.w(TAG, "Ignoring invalid provider : " + provider);
-            return;
-        }
-
-        final Collection<MediaRoute2Info> routes = provider.getRoutes();
+    void addRoutesOnHandler(List<MediaRoute2Info> routes) {
+        List<MediaRoute2Info> addedRoutes = new ArrayList<>();
         for (MediaRoute2Info route : routes) {
-            if (!route.isValid()) {
-                Log.w(TAG, "Ignoring invalid route : " + route);
-                continue;
+            mRoutes.put(route.getUniqueId(), route);
+            if (route.supportsControlCategory(mControlCategories)) {
+                addedRoutes.add(route);
             }
-            if (!route.supportsControlCategory(controlCategories)) {
-                continue;
-            }
-            MediaRoute2Info preRoute = findRouteById(route.getId());
-            if (!route.equals(preRoute)) {
-                notifyRouteChanged(route);
-            }
-            outRoutes.add(route);
+        }
+        if (addedRoutes.size() > 0) {
+            refreshFilteredRoutes();
+            notifyRoutesAdded(addedRoutes);
         }
     }
 
-    MediaRoute2Info findRouteById(String id) {
-        for (MediaRoute2Info route : mRoutes) {
-            if (route.getId().equals(id)) return route;
+    void removeRoutesOnHandler(List<MediaRoute2Info> routes) {
+        List<MediaRoute2Info> removedRoutes = new ArrayList<>();
+        for (MediaRoute2Info route : routes) {
+            mRoutes.remove(route.getUniqueId());
+            if (route.supportsControlCategory(mControlCategories)) {
+                removedRoutes.add(route);
+            }
         }
-        return null;
+        if (removedRoutes.size() > 0) {
+            refreshFilteredRoutes();
+            notifyRoutesRemoved(removedRoutes);
+        }
     }
 
-    void notifyRouteListChanged(List<MediaRoute2Info> routes) {
+    void changeRoutesOnHandler(List<MediaRoute2Info> routes) {
+        List<MediaRoute2Info> changedRoutes = new ArrayList<>();
+        for (MediaRoute2Info route : routes) {
+            mRoutes.put(route.getUniqueId(), route);
+            if (route.supportsControlCategory(mControlCategories)) {
+                changedRoutes.add(route);
+            }
+        }
+        if (changedRoutes.size() > 0) {
+            refreshFilteredRoutes();
+            notifyRoutesChanged(changedRoutes);
+        }
+    }
+
+    private void refreshFilteredRoutes() {
+        List<MediaRoute2Info> filteredRoutes = new ArrayList<>();
+
+        for (MediaRoute2Info route : mRoutes.values()) {
+            if (route.supportsControlCategory(mControlCategories)) {
+                filteredRoutes.add(route);
+            }
+        }
+        mFilteredRoutes = Collections.unmodifiableList(filteredRoutes);
+    }
+
+    private void notifyRoutesAdded(List<MediaRoute2Info> routes) {
+        for (CallbackRecord record: mCallbackRecords) {
+            record.mExecutor.execute(
+                    () -> record.mCallback.onRoutesAdded(routes));
+        }
+    }
+
+    private void notifyRoutesRemoved(List<MediaRoute2Info> routes) {
+        for (CallbackRecord record: mCallbackRecords) {
+            record.mExecutor.execute(
+                    () -> record.mCallback.onRoutesRemoved(routes));
+        }
+    }
+
+    private void notifyRoutesChanged(List<MediaRoute2Info> routes) {
         for (CallbackRecord record: mCallbackRecords) {
             record.mExecutor.execute(
                     () -> record.mCallback.onRoutesChanged(routes));
         }
     }
 
-    void notifyRouteChanged(MediaRoute2Info route) {
-        for (CallbackRecord record: mCallbackRecords) {
-            record.mExecutor.execute(
-                    () -> record.mCallback.onRouteChanged(route));
-        }
-    }
-
     /**
      * Interface for receiving events about media routing changes.
      */
     public static class Callback {
         //TODO: clean up these callbacks
-        /**
-         * Called when a route is added.
-         */
-        public void onRouteAdded(MediaRoute2Info routeInfo) {}
 
         /**
-         * Called when a route is changed.
+         * Called when routes are added.
+         * @param routes the list of routes that have been added. It's never empty.
          */
-        public void onRouteChanged(MediaRoute2Info routeInfo) {}
+        public void onRoutesAdded(@NonNull List<MediaRoute2Info> routes) {}
 
         /**
-         * Called when a route is removed.
+         * Called when routes are removed.
+         * @param routes the list of routes that have been removed. It's never empty.
          */
-        public void onRouteRemoved(MediaRoute2Info routeInfo) {}
+        public void onRoutesRemoved(@NonNull List<MediaRoute2Info> routes) {}
 
         /**
-         * Called when the list of routes is changed.
+         * Called when routes are changed.
+         * @param routes the list of routes that have been changed. It's never empty.
          */
         public void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) {}
     }
@@ -436,11 +473,10 @@
         }
 
         void notifyRoutes() {
-            final List<MediaRoute2Info> routes = mRoutes;
+            final List<MediaRoute2Info> routes = mFilteredRoutes;
             // notify only when bound to media router service.
-            //TODO: Correct the condition when control category, default route, .. are finalized.
             if (routes.size() > 0) {
-                mExecutor.execute(() -> mCallback.onRoutesChanged(routes));
+                mExecutor.execute(() -> mCallback.onRoutesAdded(routes));
             }
         }
     }
@@ -450,9 +486,21 @@
         public void notifyRestoreRoute() throws RemoteException {}
 
         @Override
-        public void notifyProviderInfosUpdated(List<MediaRoute2ProviderInfo> info) {
-            mHandler.sendMessage(obtainMessage(MediaRouter2::onProviderInfosUpdated,
-                    MediaRouter2.this, info));
+        public void notifyRoutesAdded(List<MediaRoute2Info> routes) {
+            mHandler.sendMessage(obtainMessage(MediaRouter2::addRoutesOnHandler,
+                    MediaRouter2.this, routes));
+        }
+
+        @Override
+        public void notifyRoutesRemoved(List<MediaRoute2Info> routes) {
+            mHandler.sendMessage(obtainMessage(MediaRouter2::removeRoutesOnHandler,
+                    MediaRouter2.this, routes));
+        }
+
+        @Override
+        public void notifyRoutesChanged(List<MediaRoute2Info> routes) {
+            mHandler.sendMessage(obtainMessage(MediaRouter2::changeRoutesOnHandler,
+                    MediaRouter2.this, routes));
         }
     }
 }
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 0d7b6ff..7e848a0 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -67,7 +67,7 @@
     @NonNull
     List<MediaRoute2Info> mRoutes = Collections.emptyList();
     @NonNull
-    ConcurrentMap<String, List<String>> mControlCategoryMap = new ConcurrentHashMap<>();
+    final ConcurrentMap<String, List<String>> mControlCategoryMap = new ConcurrentHashMap<>();
 
     /**
      * Gets an instance of media router manager that controls media route of other applications.
@@ -427,6 +427,8 @@
          * A client may refresh available routes for each application.
          */
         public void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) {}
+
+        //TODO: add onControlCategoriesChanged to notify available routes are changed
     }
 
     final class CallbackRecord {
diff --git a/media/java/android/media/Utils.java b/media/java/android/media/Utils.java
index 5b62f16..d942bb6 100644
--- a/media/java/android/media/Utils.java
+++ b/media/java/android/media/Utils.java
@@ -16,8 +16,8 @@
 
 package android.media;
 
-import android.content.Context;
 import android.content.ContentResolver;
+import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Environment;
@@ -206,12 +206,13 @@
     }
 
     static Size parseSize(Object o, Size fallback) {
+        if (o == null) {
+            return fallback;
+        }
         try {
             return Size.parseSize((String) o);
         } catch (ClassCastException e) {
         } catch (NumberFormatException e) {
-        } catch (NullPointerException e) {
-            return fallback;
         }
         Log.w(TAG, "could not parse size '" + o + "'");
         return fallback;
@@ -226,14 +227,15 @@
             return Integer.parseInt(s);
         } catch (ClassCastException e) {
         } catch (NumberFormatException e) {
-        } catch (NullPointerException e) {
-            return fallback;
         }
         Log.w(TAG, "could not parse integer '" + o + "'");
         return fallback;
     }
 
     static Range<Integer> parseIntRange(Object o, Range<Integer> fallback) {
+        if (o == null) {
+            return fallback;
+        }
         try {
             String s = (String)o;
             int ix = s.indexOf('-');
@@ -246,8 +248,6 @@
             return Range.create(value, value);
         } catch (ClassCastException e) {
         } catch (NumberFormatException e) {
-        } catch (NullPointerException e) {
-            return fallback;
         } catch (IllegalArgumentException e) {
         }
         Log.w(TAG, "could not parse integer range '" + o + "'");
@@ -255,6 +255,9 @@
     }
 
     static Range<Long> parseLongRange(Object o, Range<Long> fallback) {
+        if (o == null) {
+            return fallback;
+        }
         try {
             String s = (String)o;
             int ix = s.indexOf('-');
@@ -267,8 +270,6 @@
             return Range.create(value, value);
         } catch (ClassCastException e) {
         } catch (NumberFormatException e) {
-        } catch (NullPointerException e) {
-            return fallback;
         } catch (IllegalArgumentException e) {
         }
         Log.w(TAG, "could not parse long range '" + o + "'");
@@ -276,6 +277,9 @@
     }
 
     static Range<Rational> parseRationalRange(Object o, Range<Rational> fallback) {
+        if (o == null) {
+            return fallback;
+        }
         try {
             String s = (String)o;
             int ix = s.indexOf('-');
@@ -288,8 +292,6 @@
             return Range.create(value, value);
         } catch (ClassCastException e) {
         } catch (NumberFormatException e) {
-        } catch (NullPointerException e) {
-            return fallback;
         } catch (IllegalArgumentException e) {
         }
         Log.w(TAG, "could not parse rational range '" + o + "'");
@@ -297,6 +299,9 @@
     }
 
     static Pair<Size, Size> parseSizeRange(Object o) {
+        if (o == null) {
+            return null;
+        }
         try {
             String s = (String)o;
             int ix = s.indexOf('-');
@@ -309,8 +314,6 @@
             return Pair.create(value, value);
         } catch (ClassCastException e) {
         } catch (NumberFormatException e) {
-        } catch (NullPointerException e) {
-            return null;
         } catch (IllegalArgumentException e) {
         }
         Log.w(TAG, "could not parse size range '" + o + "'");
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 39474e1..01f1250 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -853,6 +853,10 @@
                 Log.v(TAG, "notifyVolumeAdjust: " + adjustment);
             }
         }
+
+        public void notifyUnregistration() {
+            setRegistration(null);
+        }
     };
 
     //==================================================
diff --git a/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl b/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl
index 107e7cd..1d58151 100644
--- a/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl
+++ b/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl
@@ -34,4 +34,8 @@
 
     // callback for volume events
     void notifyVolumeAdjust(int adjustment);
+
+    // callback for unregistration (e.g. if policy couldn't automatically be re-registered after
+    // an audioserver crash)
+    void notifyUnregistration();
 }
diff --git a/media/java/android/media/midi/MidiDeviceInfo.aidl b/media/java/android/media/midi/MidiDeviceInfo.aidl
index 5b2ac9b..a248204 100644
--- a/media/java/android/media/midi/MidiDeviceInfo.aidl
+++ b/media/java/android/media/midi/MidiDeviceInfo.aidl
@@ -16,4 +16,4 @@
 
 package android.media.midi;
 
-parcelable MidiDeviceInfo cpp_header "media/MidiDeviceInfo.h";
+parcelable MidiDeviceInfo cpp_header "MidiDeviceInfo.h";
diff --git a/media/java/android/media/tv/OWNER b/media/java/android/media/tv/OWNER
new file mode 100644
index 0000000..64c0bb5
--- /dev/null
+++ b/media/java/android/media/tv/OWNER
@@ -0,0 +1,5 @@
+amyjojo@google.com
+nchalko@google.com
+shubang@google.com
+quxiangfang@google.com
+
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
new file mode 100644
index 0000000..d1c171a
--- /dev/null
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+package android.media.tv.tuner;
+
+import java.util.List;
+
+/**
+ * Tuner is used to interact with tuner devices.
+ *
+ * @hide
+ */
+public final class Tuner implements AutoCloseable  {
+    private static final String TAG = "MediaTvTuner";
+    private static final boolean DEBUG = false;
+
+    private static final int MSG_ON_FRONTEND_EVENT = 1;
+
+    static {
+        System.loadLibrary("media_tv_tuner");
+        nativeInit();
+    }
+
+    private FrontendCallback mFrontendCallback;
+    private List<Integer> mFrontendIds;
+
+    public Tuner() {
+        nativeSetup();
+    }
+
+    private long mNativeContext; // used by native jMediaTuner
+
+    @Override
+    public void close() {}
+
+    /**
+     * Native Initialization.
+     */
+    private static native void nativeInit();
+
+    /**
+     * Native setup.
+     */
+    private native void nativeSetup();
+
+    /**
+     * Native method to get all frontend IDs.
+     */
+    private native List<Integer> nativeGetFrontendIds();
+
+    /**
+     * Native method to open frontend of the given ID.
+     */
+    private native Frontend nativeOpenFrontendById(int id);
+
+    private native Filter nativeOpenFilter(int type, int subType, int bufferSize);
+
+
+    /**
+     * Frontend Callback.
+     */
+    public interface FrontendCallback {
+
+        /**
+         * Invoked when there is a frontend event.
+         */
+        void onEvent(int frontendEventType);
+    }
+
+    protected static class Frontend {
+        int mId;
+        private Frontend(int id) {
+            mId = id;
+        }
+    }
+
+    private List<Integer> getFrontendIds() {
+        mFrontendIds = nativeGetFrontendIds();
+        return mFrontendIds;
+    }
+
+    private Frontend openFrontendById(int id) {
+        if (mFrontendIds == null) {
+            getFrontendIds();
+        }
+        if (!mFrontendIds.contains(id)) {
+            return null;
+        }
+        return nativeOpenFrontendById(id);
+    }
+
+    protected class Filter {
+        int mId;
+        private Filter(int id) {
+            mId = id;
+        }
+    }
+
+    private Filter openFilter(int type, int subType, int bufferSize) {
+        return nativeOpenFilter(type, subType, bufferSize);
+    }
+}
diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java
new file mode 100644
index 0000000..411882e
--- /dev/null
+++ b/media/java/android/media/tv/tuner/TunerConstants.java
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+package android.media.tv.tuner;
+
+import android.annotation.IntDef;
+import android.hardware.tv.tuner.V1_0.Constants;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * @hide
+ */
+final class TunerConstants {
+    public static final int INVALID_TS_PID = Constants.Constant.INVALID_TS_PID;
+    public static final int INVALID_STREAM_ID = Constants.Constant.INVALID_STREAM_ID;
+
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({FRONTEND_TYPE_UNDEFINED, FRONTEND_TYPE_ANALOG, FRONTEND_TYPE_ATSC, FRONTEND_TYPE_ATSC3,
+            FRONTEND_TYPE_DVBC, FRONTEND_TYPE_DVBS, FRONTEND_TYPE_DVBT, FRONTEND_TYPE_ISDBS,
+            FRONTEND_TYPE_ISDBS3, FRONTEND_TYPE_ISDBT})
+    public @interface FrontendType {}
+
+    public static final int FRONTEND_TYPE_UNDEFINED = Constants.FrontendType.UNDEFINED;
+    public static final int FRONTEND_TYPE_ANALOG = Constants.FrontendType.ANALOG;
+    public static final int FRONTEND_TYPE_ATSC = Constants.FrontendType.ATSC;
+    public static final int FRONTEND_TYPE_ATSC3 = Constants.FrontendType.ATSC3;
+    public static final int FRONTEND_TYPE_DVBC = Constants.FrontendType.DVBC;
+    public static final int FRONTEND_TYPE_DVBS = Constants.FrontendType.DVBS;
+    public static final int FRONTEND_TYPE_DVBT = Constants.FrontendType.DVBT;
+    public static final int FRONTEND_TYPE_ISDBS = Constants.FrontendType.ISDBS;
+    public static final int FRONTEND_TYPE_ISDBS3 = Constants.FrontendType.ISDBS3;
+    public static final int FRONTEND_TYPE_ISDBT = Constants.FrontendType.ISDBT;
+
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({FRONTEND_EVENT_TYPE_LOCKED, FRONTEND_EVENT_TYPE_NO_SIGNAL,
+            FRONTEND_EVENT_TYPE_LOST_LOCK})
+    public @interface FrontendEventType {}
+
+    public static final int FRONTEND_EVENT_TYPE_LOCKED = Constants.FrontendEventType.LOCKED;
+    public static final int FRONTEND_EVENT_TYPE_NO_SIGNAL = Constants.FrontendEventType.NO_SIGNAL;
+    public static final int FRONTEND_EVENT_TYPE_LOST_LOCK = Constants.FrontendEventType.LOST_LOCK;
+
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({DATA_FORMAT_TS, DATA_FORMAT_PES, DATA_FORMAT_ES, DATA_FORMAT_SHV_TLV})
+    public @interface DataFormat {}
+
+    public static final int DATA_FORMAT_TS = Constants.DataFormat.TS;
+    public static final int DATA_FORMAT_PES = Constants.DataFormat.PES;
+    public static final int DATA_FORMAT_ES = Constants.DataFormat.ES;
+    public static final int DATA_FORMAT_SHV_TLV = Constants.DataFormat.SHV_TLV;
+
+    private TunerConstants() {
+    }
+}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index b4edabf..2f53cbb 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -99,13 +99,14 @@
         "android_media_Utils.cpp",
     ],
 
+    header_libs: [
+        "libgui_headers",
+    ],
+
     shared_libs: [
         "liblog",
-        "libgui",
-        "libnativewindow",
         "libui",
         "libutils",
-        "android.hidl.token@1.0-utils",
     ],
 
     include_dirs: [
@@ -123,6 +124,31 @@
     ],
 }
 
+cc_library_shared {
+    name: "libmedia_tv_tuner",
+    srcs: [
+        "android_media_tv_Tuner.cpp",
+    ],
+
+    shared_libs: [
+        "android.hardware.tv.tuner@1.0",
+        "libandroid_runtime",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+
+    export_include_dirs: ["."],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+}
+
 subdirs = [
     "audioeffect",
     "soundpool",
diff --git a/media/jni/OWNERS b/media/jni/OWNERS
index bb91d4b..f1b0237 100644
--- a/media/jni/OWNERS
+++ b/media/jni/OWNERS
@@ -1,2 +1,5 @@
 # extra for MTP related files
 per-file android_mtp_*.cpp=marcone@google.com,jsharkey@android.com,jameswei@google.com,rmojumder@google.com
+
+# extra for TV related files
+per-file android_media_tv_*=nchalko@google.com,quxiangfang@google.com
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
new file mode 100644
index 0000000..9e96b74
--- /dev/null
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -0,0 +1,281 @@
+/*
+ * 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_TAG "TvTuner-JNI"
+#include <utils/Log.h>
+
+#include "android_media_tv_Tuner.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+#pragma GCC diagnostic ignored "-Wunused-function"
+
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
+using ::android::hardware::tv::tuner::V1_0::ITuner;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+struct fields_t {
+    jfieldID context;
+    jmethodID frontendInitID;
+    jmethodID filterInitID;
+};
+
+static fields_t gFields;
+
+namespace android {
+/////////////// FilterCallback ///////////////////////
+//TODO: implement filter callback
+Return<void> FilterCallback::onFilterEvent(const DemuxFilterEvent& /* filterEvent */) {
+    ALOGD("FilterCallback::onFilterEvent");
+    return Void();
+}
+Return<void> FilterCallback::onFilterStatus(const DemuxFilterStatus /*status*/) {
+    ALOGD("FilterCallback::onFilterStatu");
+    return Void();
+}
+
+/////////////// Tuner ///////////////////////
+sp<ITuner> JTuner::mTuner;
+
+JTuner::JTuner(JNIEnv *env, jobject thiz)
+    : mClass(NULL) {
+    jclass clazz = env->GetObjectClass(thiz);
+    CHECK(clazz != NULL);
+
+    mClass = (jclass)env->NewGlobalRef(clazz);
+    mObject = env->NewWeakGlobalRef(thiz);
+    if (mTuner == NULL) {
+        mTuner = getTunerService();
+    }
+}
+
+JTuner::~JTuner() {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+    env->DeleteGlobalRef(mClass);
+    mTuner = NULL;
+    mClass = NULL;
+    mObject = NULL;
+}
+
+sp<ITuner> JTuner::getTunerService() {
+    if (mTuner == nullptr) {
+        mTuner = ITuner::getService();
+
+        if (mTuner == nullptr) {
+            ALOGW("Failed to get tuner service.");
+        }
+    }
+    return mTuner;
+}
+
+jobject JTuner::getFrontendIds() {
+    ALOGD("JTuner::getFrontendIds()");
+    hidl_vec<FrontendId> feIds;
+    mTuner->getFrontendIds([&](Result, const hidl_vec<FrontendId>& frontendIds) {
+        feIds = frontendIds;
+    });
+    if (feIds.size() == 0) {
+        ALOGW("Frontend isn't available");
+        return NULL;
+    }
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jclass arrayListClazz = env->FindClass("java/util/ArrayList");
+    jmethodID arrayListAdd = env->GetMethodID(arrayListClazz, "add", "(Ljava/lang/Object;)Z");
+    jobject obj = env->NewObject(arrayListClazz, env->GetMethodID(arrayListClazz, "<init>", "()V"));
+
+    jclass integerClazz = env->FindClass("java/lang/Integer");
+    jmethodID intInit = env->GetMethodID(integerClazz, "<init>", "(I)V");
+
+    for (int i=0; i < feIds.size(); i++) {
+       jobject idObj = env->NewObject(integerClazz, intInit, feIds[i]);
+       env->CallBooleanMethod(obj, arrayListAdd, idObj);
+    }
+    return obj;
+}
+
+jobject JTuner::openFrontendById(int id) {
+    mTuner->openFrontendById(id, [&](Result, const sp<IFrontend>& frontend) {
+        mFe = frontend;
+    });
+    if (mFe == nullptr) {
+        ALOGE("Failed to open frontend");
+        return NULL;
+    }
+
+    jint jId = (jint) id;
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    // TODO: add more fields to frontend
+    return env->NewObject(
+            env->FindClass("android/media/tv/tuner/Tuner$Frontend"),
+            gFields.frontendInitID,
+            (jint) jId);
+}
+
+bool JTuner::openDemux() {
+    if (mTuner == nullptr) {
+        return false;
+    }
+    if (mDemux != nullptr) {
+        return true;
+    }
+    mTuner->openDemux([&](Result, uint32_t demuxId, const sp<IDemux>& demux) {
+        mDemux = demux;
+        mDemuxId = demuxId;
+        ALOGD("open demux, id = %d", demuxId);
+    });
+    if (mDemux == nullptr) {
+        return false;
+    }
+    return true;
+}
+
+jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) {
+    if (mDemux == NULL) {
+        if (!openDemux()) {
+            return NULL;
+        }
+    }
+
+    sp<IFilter> f;
+    mDemux->openFilter(type, bufferSize, new FilterCallback,
+            [&](Result, const sp<IFilter>& filter) {
+                f = filter;
+            });
+    if (f == NULL) {
+        ALOGD("Failed to open filter, type = %d", type.mainType);
+        return NULL;
+    }
+    int fId;
+    f->getId([&](Result, uint32_t filterId) {
+        fId = filterId;
+    });
+    mFilters[fId] = f;
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    return env->NewObject(
+            env->FindClass("android/media/tv/tuner/Tuner$Filter"),
+            gFields.filterInitID,
+            mObject,
+            (jint) fId);
+}
+
+}  // namespace android
+
+////////////////////////////////////////////////////////////////////////////////
+
+using namespace android;
+
+static sp<JTuner> setTuner(JNIEnv *env, jobject thiz, const sp<JTuner> &tuner) {
+    sp<JTuner> old = (JTuner *)env->GetLongField(thiz, gFields.context);
+
+    if (tuner != NULL) {
+        tuner->incStrong(thiz);
+    }
+    if (old != NULL) {
+        old->decStrong(thiz);
+    }
+    env->SetLongField(thiz, gFields.context, (jlong)tuner.get());
+
+    return old;
+}
+
+static sp<JTuner> getTuner(JNIEnv *env, jobject thiz) {
+    return (JTuner *)env->GetLongField(thiz, gFields.context);
+}
+
+static void android_media_tv_Tuner_native_init(JNIEnv *env) {
+    jclass clazz = env->FindClass("android/media/tv/tuner/Tuner");
+    CHECK(clazz != NULL);
+
+    gFields.context = env->GetFieldID(clazz, "mNativeContext", "J");
+    CHECK(gFields.context != NULL);
+
+    jclass frontendClazz = env->FindClass("android/media/tv/tuner/Tuner$Frontend");
+    gFields.frontendInitID = env->GetMethodID(frontendClazz, "<init>", "(I)V");
+
+    jclass filterClazz = env->FindClass("android/media/tv/tuner/Tuner$Filter");
+    gFields.filterInitID =
+            env->GetMethodID(filterClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;I)V");
+}
+
+static void android_media_tv_Tuner_native_setup(JNIEnv *env, jobject thiz) {
+    sp<JTuner> tuner = new JTuner(env, thiz);
+    setTuner(env,thiz, tuner);
+}
+
+static jobject android_media_tv_Tuner_get_frontend_ids(JNIEnv *env, jobject thiz) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    return tuner->getFrontendIds();
+}
+
+static jobject android_media_tv_Tuner_open_frontend_by_id(JNIEnv *env, jobject thiz, jint id) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    return tuner->openFrontendById(id);
+}
+
+static jobject android_media_tv_Tuner_open_filter(
+        JNIEnv *env, jobject thiz, jint type, jint subType, jint bufferSize) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    DemuxFilterType filterType {
+        .mainType = static_cast<DemuxFilterMainType>(type),
+    };
+
+    // TODO: other sub types
+    filterType.subType.tsFilterType(static_cast<DemuxTsFilterType>(subType));
+
+    return tuner->openFilter(filterType, bufferSize);
+}
+
+static const JNINativeMethod gMethods[] = {
+    { "nativeInit", "()V", (void *)android_media_tv_Tuner_native_init },
+    { "nativeSetup", "()V", (void *)android_media_tv_Tuner_native_setup },
+    { "nativeGetFrontendIds", "()Ljava/util/List;",
+            (void *)android_media_tv_Tuner_get_frontend_ids },
+    { "nativeOpenFrontendById", "(I)Landroid/media/tv/tuner/Tuner$Frontend;",
+            (void *)android_media_tv_Tuner_open_frontend_by_id },
+    { "nativeOpenFilter", "(III)Landroid/media/tv/tuner/Tuner$Filter;",
+            (void *)android_media_tv_Tuner_open_filter },
+};
+
+static int register_android_media_tv_Tuner(JNIEnv *env) {
+    return AndroidRuntime::registerNativeMethods(
+            env, "android/media/tv/tuner/Tuner", gMethods, NELEM(gMethods));
+}
+
+jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
+{
+    JNIEnv* env = NULL;
+    jint result = -1;
+
+    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+        ALOGE("ERROR: GetEnv failed\n");
+        return result;
+    }
+    assert(env != NULL);
+
+    if (register_android_media_tv_Tuner(env) != JNI_OK) {
+        ALOGE("ERROR: Tuner native registration failed\n");
+        return result;
+    }
+    return JNI_VERSION_1_4;
+}
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
new file mode 100644
index 0000000..b23b394
--- /dev/null
+++ b/media/jni/android_media_tv_Tuner.h
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+#ifndef _ANDROID_MEDIA_TV_TUNER_H_
+#define _ANDROID_MEDIA_TV_TUNER_H_
+
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <unordered_map>
+#include <utils/RefBase.h>
+
+#include "jni.h"
+
+using ::android::hardware::Return;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterType;
+using ::android::hardware::tv::tuner::V1_0::FrontendId;
+using ::android::hardware::tv::tuner::V1_0::IDemux;
+using ::android::hardware::tv::tuner::V1_0::IFilter;
+using ::android::hardware::tv::tuner::V1_0::IFilterCallback;
+using ::android::hardware::tv::tuner::V1_0::IFrontend;
+using ::android::hardware::tv::tuner::V1_0::ITuner;
+
+namespace android {
+
+struct FilterCallback : public IFilterCallback {
+    virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent);
+    virtual Return<void> onFilterStatus(const DemuxFilterStatus status);
+};
+
+struct JTuner : public RefBase {
+    JTuner(JNIEnv *env, jobject thiz);
+    sp<ITuner> getTunerService();
+    jobject getFrontendIds();
+    jobject openFrontendById(int id);
+    jobject openFilter(DemuxFilterType type, int bufferSize);
+protected:
+    bool openDemux();
+    virtual ~JTuner();
+
+private:
+    jclass mClass;
+    jweak mObject;
+    static sp<ITuner> mTuner;
+    sp<IFrontend> mFe;
+    sp<IDemux> mDemux;
+    int mDemuxId;
+    std::unordered_map<int, sp<IFilter>> mFilters;
+};
+
+}  // namespace android
+
+#endif  // _ANDROID_MEDIA_TV_TUNER_H_
diff --git a/media/jni/audioeffect/Android.bp b/media/jni/audioeffect/Android.bp
index 09c546a..41ab670 100644
--- a/media/jni/audioeffect/Android.bp
+++ b/media/jni/audioeffect/Android.bp
@@ -6,6 +6,7 @@
         "android_media_SourceDefaultEffect.cpp",
         "android_media_StreamDefaultEffect.cpp",
         "android_media_Visualizer.cpp",
+        "Visualizer.cpp",
     ],
 
     shared_libs: [
@@ -14,10 +15,12 @@
         "libutils",
         "libandroid_runtime",
         "libnativehelper",
-        "libmedia",
         "libaudioclient",
+        "libaudioutils",
     ],
 
+    version_script: "exports.lds",
+
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/media/jni/audioeffect/Visualizer.cpp b/media/jni/audioeffect/Visualizer.cpp
new file mode 100644
index 0000000..83f3b6e
--- /dev/null
+++ b/media/jni/audioeffect/Visualizer.cpp
@@ -0,0 +1,446 @@
+/*
+**
+** Copyright 2010, 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 "Visualizer"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include <audio_utils/fixedfft.h>
+#include <utils/Thread.h>
+
+#include "Visualizer.h"
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+Visualizer::Visualizer (const String16& opPackageName,
+         int32_t priority,
+         effect_callback_t cbf,
+         void* user,
+         audio_session_t sessionId)
+    :   AudioEffect(SL_IID_VISUALIZATION, opPackageName, NULL, priority, cbf, user, sessionId),
+        mCaptureRate(CAPTURE_RATE_DEF),
+        mCaptureSize(CAPTURE_SIZE_DEF),
+        mSampleRate(44100000),
+        mScalingMode(VISUALIZER_SCALING_MODE_NORMALIZED),
+        mMeasurementMode(MEASUREMENT_MODE_NONE),
+        mCaptureCallBack(NULL),
+        mCaptureCbkUser(NULL)
+{
+    initCaptureSize();
+}
+
+Visualizer::~Visualizer()
+{
+    ALOGV("Visualizer::~Visualizer()");
+    setEnabled(false);
+    setCaptureCallBack(NULL, NULL, 0, 0);
+}
+
+void Visualizer::release()
+{
+    ALOGV("Visualizer::release()");
+    setEnabled(false);
+    Mutex::Autolock _l(mCaptureLock);
+
+    mCaptureThread.clear();
+    mCaptureCallBack = NULL;
+    mCaptureCbkUser = NULL;
+    mCaptureFlags = 0;
+    mCaptureRate = 0;
+}
+
+status_t Visualizer::setEnabled(bool enabled)
+{
+    Mutex::Autolock _l(mCaptureLock);
+
+    sp<CaptureThread> t = mCaptureThread;
+    if (t != 0) {
+        if (enabled) {
+            if (t->exitPending()) {
+                mCaptureLock.unlock();
+                if (t->requestExitAndWait() == WOULD_BLOCK) {
+                    mCaptureLock.lock();
+                    ALOGE("Visualizer::enable() called from thread");
+                    return INVALID_OPERATION;
+                }
+                mCaptureLock.lock();
+            }
+        }
+        t->mLock.lock();
+    }
+
+    status_t status = AudioEffect::setEnabled(enabled);
+
+    if (t != 0) {
+        if (enabled && status == NO_ERROR) {
+            t->run("Visualizer");
+        } else {
+            t->requestExit();
+        }
+    }
+
+    if (t != 0) {
+        t->mLock.unlock();
+    }
+
+    return status;
+}
+
+status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags,
+        uint32_t rate)
+{
+    if (rate > CAPTURE_RATE_MAX) {
+        return BAD_VALUE;
+    }
+    Mutex::Autolock _l(mCaptureLock);
+
+    if (mEnabled) {
+        return INVALID_OPERATION;
+    }
+
+    if (mCaptureThread != 0) {
+        mCaptureLock.unlock();
+        mCaptureThread->requestExitAndWait();
+        mCaptureLock.lock();
+    }
+
+    mCaptureThread.clear();
+    mCaptureCallBack = cbk;
+    mCaptureCbkUser = user;
+    mCaptureFlags = flags;
+    mCaptureRate = rate;
+
+    if (cbk != NULL) {
+        mCaptureThread = new CaptureThread(this, rate, ((flags & CAPTURE_CALL_JAVA) != 0));
+    }
+    ALOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x",
+            rate, mCaptureThread.get(), mCaptureFlags);
+    return NO_ERROR;
+}
+
+status_t Visualizer::setCaptureSize(uint32_t size)
+{
+    if (size > VISUALIZER_CAPTURE_SIZE_MAX ||
+        size < VISUALIZER_CAPTURE_SIZE_MIN ||
+        popcount(size) != 1) {
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock _l(mCaptureLock);
+    if (mEnabled) {
+        return INVALID_OPERATION;
+    }
+
+    uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
+    effect_param_t *p = (effect_param_t *)buf32;
+
+    p->psize = sizeof(uint32_t);
+    p->vsize = sizeof(uint32_t);
+    *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE;
+    *((int32_t *)p->data + 1)= size;
+    status_t status = setParameter(p);
+
+    ALOGV("setCaptureSize size %d  status %d p->status %d", size, status, p->status);
+
+    if (status == NO_ERROR) {
+        status = p->status;
+        if (status == NO_ERROR) {
+            mCaptureSize = size;
+        }
+    }
+
+    return status;
+}
+
+status_t Visualizer::setScalingMode(uint32_t mode) {
+    if ((mode != VISUALIZER_SCALING_MODE_NORMALIZED)
+            && (mode != VISUALIZER_SCALING_MODE_AS_PLAYED)) {
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock _l(mCaptureLock);
+
+    uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
+    effect_param_t *p = (effect_param_t *)buf32;
+
+    p->psize = sizeof(uint32_t);
+    p->vsize = sizeof(uint32_t);
+    *(int32_t *)p->data = VISUALIZER_PARAM_SCALING_MODE;
+    *((int32_t *)p->data + 1)= mode;
+    status_t status = setParameter(p);
+
+    ALOGV("setScalingMode mode %d  status %d p->status %d", mode, status, p->status);
+
+    if (status == NO_ERROR) {
+        status = p->status;
+        if (status == NO_ERROR) {
+            mScalingMode = mode;
+        }
+    }
+
+    return status;
+}
+
+status_t Visualizer::setMeasurementMode(uint32_t mode) {
+    if ((mode != MEASUREMENT_MODE_NONE)
+            //Note: needs to be handled as a mask when more measurement modes are added
+            && ((mode & MEASUREMENT_MODE_PEAK_RMS) != mode)) {
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock _l(mCaptureLock);
+
+    uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
+    effect_param_t *p = (effect_param_t *)buf32;
+
+    p->psize = sizeof(uint32_t);
+    p->vsize = sizeof(uint32_t);
+    *(int32_t *)p->data = VISUALIZER_PARAM_MEASUREMENT_MODE;
+    *((int32_t *)p->data + 1)= mode;
+    status_t status = setParameter(p);
+
+    ALOGV("setMeasurementMode mode %d  status %d p->status %d", mode, status, p->status);
+
+    if (status == NO_ERROR) {
+        status = p->status;
+        if (status == NO_ERROR) {
+            mMeasurementMode = mode;
+        }
+    }
+    return status;
+}
+
+status_t Visualizer::getIntMeasurements(uint32_t type, uint32_t number, int32_t *measurements) {
+    if (mMeasurementMode == MEASUREMENT_MODE_NONE) {
+        ALOGE("Cannot retrieve int measurements, no measurement mode set");
+        return INVALID_OPERATION;
+    }
+    if (!(mMeasurementMode & type)) {
+        // measurement type has not been set on this Visualizer
+        ALOGE("Cannot retrieve int measurements, requested measurement mode 0x%x not set(0x%x)",
+                type, mMeasurementMode);
+        return INVALID_OPERATION;
+    }
+    // only peak+RMS measurement supported
+    if ((type != MEASUREMENT_MODE_PEAK_RMS)
+            // for peak+RMS measurement, the results are 2 int32_t values
+            || (number != 2)) {
+        ALOGE("Cannot retrieve int measurements, MEASUREMENT_MODE_PEAK_RMS returns 2 ints, not %d",
+                        number);
+        return BAD_VALUE;
+    }
+
+    status_t status = NO_ERROR;
+    if (mEnabled) {
+        uint32_t replySize = number * sizeof(int32_t);
+        status = command(VISUALIZER_CMD_MEASURE,
+                sizeof(uint32_t)  /*cmdSize*/,
+                &type /*cmdData*/,
+                &replySize, measurements);
+        ALOGV("getMeasurements() command returned %d", status);
+        if ((status == NO_ERROR) && (replySize == 0)) {
+            status = NOT_ENOUGH_DATA;
+        }
+    } else {
+        ALOGV("getMeasurements() disabled");
+        return INVALID_OPERATION;
+    }
+    return status;
+}
+
+status_t Visualizer::getWaveForm(uint8_t *waveform)
+{
+    if (waveform == NULL) {
+        return BAD_VALUE;
+    }
+    if (mCaptureSize == 0) {
+        return NO_INIT;
+    }
+
+    status_t status = NO_ERROR;
+    if (mEnabled) {
+        uint32_t replySize = mCaptureSize;
+        status = command(VISUALIZER_CMD_CAPTURE, 0, NULL, &replySize, waveform);
+        ALOGV("getWaveForm() command returned %d", status);
+        if ((status == NO_ERROR) && (replySize == 0)) {
+            status = NOT_ENOUGH_DATA;
+        }
+    } else {
+        ALOGV("getWaveForm() disabled");
+        memset(waveform, 0x80, mCaptureSize);
+    }
+    return status;
+}
+
+status_t Visualizer::getFft(uint8_t *fft)
+{
+    if (fft == NULL) {
+        return BAD_VALUE;
+    }
+    if (mCaptureSize == 0) {
+        return NO_INIT;
+    }
+
+    status_t status = NO_ERROR;
+    if (mEnabled) {
+        uint8_t buf[mCaptureSize];
+        status = getWaveForm(buf);
+        if (status == NO_ERROR) {
+            status = doFft(fft, buf);
+        }
+    } else {
+        memset(fft, 0, mCaptureSize);
+    }
+    return status;
+}
+
+status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
+{
+    int32_t workspace[mCaptureSize >> 1];
+    int32_t nonzero = 0;
+
+    for (uint32_t i = 0; i < mCaptureSize; i += 2) {
+        workspace[i >> 1] =
+                ((waveform[i] ^ 0x80) << 24) | ((waveform[i + 1] ^ 0x80) << 8);
+        nonzero |= workspace[i >> 1];
+    }
+
+    if (nonzero) {
+        fixed_fft_real(mCaptureSize >> 1, workspace);
+    }
+
+    for (uint32_t i = 0; i < mCaptureSize; i += 2) {
+        short tmp = workspace[i >> 1] >> 21;
+        while (tmp > 127 || tmp < -128) tmp >>= 1;
+        fft[i] = tmp;
+        tmp = workspace[i >> 1];
+        tmp >>= 5;
+        while (tmp > 127 || tmp < -128) tmp >>= 1;
+        fft[i + 1] = tmp;
+    }
+
+    return NO_ERROR;
+}
+
+void Visualizer::periodicCapture()
+{
+    Mutex::Autolock _l(mCaptureLock);
+    ALOGV("periodicCapture() %p mCaptureCallBack %p mCaptureFlags 0x%08x",
+            this, mCaptureCallBack, mCaptureFlags);
+    if (mCaptureCallBack != NULL &&
+        (mCaptureFlags & (CAPTURE_WAVEFORM|CAPTURE_FFT)) &&
+        mCaptureSize != 0) {
+        uint8_t waveform[mCaptureSize];
+        status_t status = getWaveForm(waveform);
+        if (status != NO_ERROR) {
+            return;
+        }
+        uint8_t fft[mCaptureSize];
+        if (mCaptureFlags & CAPTURE_FFT) {
+            status = doFft(fft, waveform);
+        }
+        if (status != NO_ERROR) {
+            return;
+        }
+        uint8_t *wavePtr = NULL;
+        uint8_t *fftPtr = NULL;
+        uint32_t waveSize = 0;
+        uint32_t fftSize = 0;
+        if (mCaptureFlags & CAPTURE_WAVEFORM) {
+            wavePtr = waveform;
+            waveSize = mCaptureSize;
+        }
+        if (mCaptureFlags & CAPTURE_FFT) {
+            fftPtr = fft;
+            fftSize = mCaptureSize;
+        }
+        mCaptureCallBack(mCaptureCbkUser, waveSize, wavePtr, fftSize, fftPtr, mSampleRate);
+    }
+}
+
+uint32_t Visualizer::initCaptureSize()
+{
+    uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
+    effect_param_t *p = (effect_param_t *)buf32;
+
+    p->psize = sizeof(uint32_t);
+    p->vsize = sizeof(uint32_t);
+    *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE;
+    status_t status = getParameter(p);
+
+    if (status == NO_ERROR) {
+        status = p->status;
+    }
+
+    uint32_t size = 0;
+    if (status == NO_ERROR) {
+        size = *((int32_t *)p->data + 1);
+    }
+    mCaptureSize = size;
+
+    ALOGV("initCaptureSize size %d status %d", mCaptureSize, status);
+
+    return size;
+}
+
+void Visualizer::controlStatusChanged(bool controlGranted) {
+    if (controlGranted) {
+        // this Visualizer instance regained control of the effect, reset the scaling mode
+        //   and capture size as has been cached through it.
+        ALOGV("controlStatusChanged(true) causes effect parameter reset:");
+        ALOGV("    scaling mode reset to %d", mScalingMode);
+        setScalingMode(mScalingMode);
+        ALOGV("    capture size reset to %d", mCaptureSize);
+        setCaptureSize(mCaptureSize);
+    }
+    AudioEffect::controlStatusChanged(controlGranted);
+}
+
+//-------------------------------------------------------------------------
+
+Visualizer::CaptureThread::CaptureThread(Visualizer* receiver, uint32_t captureRate,
+        bool bCanCallJava)
+    : Thread(bCanCallJava), mReceiver(receiver)
+{
+    mSleepTimeUs = 1000000000 / captureRate;
+    ALOGV("CaptureThread cstor %p captureRate %d mSleepTimeUs %d", this, captureRate, mSleepTimeUs);
+}
+
+bool Visualizer::CaptureThread::threadLoop()
+{
+    ALOGV("CaptureThread %p enter", this);
+    sp<Visualizer> receiver = mReceiver.promote();
+    if (receiver == NULL) {
+        return false;
+    }
+    while (!exitPending())
+    {
+        usleep(mSleepTimeUs);
+        receiver->periodicCapture();
+    }
+    ALOGV("CaptureThread %p exiting", this);
+    return false;
+}
+
+} // namespace android
diff --git a/media/jni/audioeffect/Visualizer.h b/media/jni/audioeffect/Visualizer.h
new file mode 100644
index 0000000..d4672a9
--- /dev/null
+++ b/media/jni/audioeffect/Visualizer.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ANDROID_MEDIA_VISUALIZER_H
+#define ANDROID_MEDIA_VISUALIZER_H
+
+#include <media/AudioEffect.h>
+#include <system/audio_effects/effect_visualizer.h>
+#include <utils/Thread.h>
+
+/**
+ * The Visualizer class enables application to retrieve part of the currently playing audio for
+ * visualization purpose. It is not an audio recording interface and only returns partial and low
+ * quality audio content. However, to protect privacy of certain audio data (e.g voice mail) the use
+ * of the visualizer requires the permission android.permission.RECORD_AUDIO.
+ * The audio session ID passed to the constructor indicates which audio content should be
+ * visualized:
+ * - If the session is 0, the audio output mix is visualized
+ * - If the session is not 0, the audio from a particular MediaPlayer or AudioTrack
+ *   using this audio session is visualized
+ * Two types of representation of audio content can be captured:
+ * - Waveform data: consecutive 8-bit (unsigned) mono samples by using the getWaveForm() method
+ * - Frequency data: 8-bit magnitude FFT by using the getFft() method
+ *
+ * The length of the capture can be retrieved or specified by calling respectively
+ * getCaptureSize() and setCaptureSize() methods. Note that the size of the FFT
+ * is half of the specified capture size but both sides of the spectrum are returned yielding in a
+ * number of bytes equal to the capture size. The capture size must be a power of 2 in the range
+ * returned by getMinCaptureSize() and getMaxCaptureSize().
+ * In addition to the polling capture mode, a callback mode is also available by installing a
+ * callback function by use of the setCaptureCallBack() method. The rate at which the callback
+ * is called as well as the type of data returned is specified.
+ * Before capturing data, the Visualizer must be enabled by calling the setEnabled() method.
+ * When data capture is not needed any more, the Visualizer should be disabled.
+ */
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class Visualizer: public AudioEffect {
+public:
+
+    enum callback_flags {
+        CAPTURE_WAVEFORM = 0x00000001,  // capture callback returns a PCM wave form
+        CAPTURE_FFT = 0x00000002,       // apture callback returns a frequency representation
+        CAPTURE_CALL_JAVA = 0x00000004  // the callback thread can call java
+    };
+
+
+    /* Constructor.
+     * See AudioEffect constructor for details on parameters.
+     */
+                        Visualizer(const String16& opPackageName,
+                                   int32_t priority = 0,
+                                   effect_callback_t cbf = NULL,
+                                   void* user = NULL,
+                                   audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX);
+
+                        ~Visualizer();
+
+    // Declared 'final' because we call this in ~Visualizer().
+    status_t    setEnabled(bool enabled) final;
+
+    // maximum capture size in samples
+    static uint32_t getMaxCaptureSize() { return VISUALIZER_CAPTURE_SIZE_MAX; }
+    // minimum capture size in samples
+    static uint32_t getMinCaptureSize() { return VISUALIZER_CAPTURE_SIZE_MIN; }
+    // maximum capture rate in millihertz
+    static uint32_t getMaxCaptureRate() { return CAPTURE_RATE_MAX; }
+
+    // callback used to return periodic PCM or FFT captures to the application. Either one or both
+    // types of data are returned (PCM and FFT) according to flags indicated when installing the
+    // callback. When a type of data is not present, the corresponding size (waveformSize or
+    // fftSize) is 0.
+    typedef void (*capture_cbk_t)(void* user,
+                                    uint32_t waveformSize,
+                                    uint8_t *waveform,
+                                    uint32_t fftSize,
+                                    uint8_t *fft,
+                                    uint32_t samplingrate);
+
+    // install a callback to receive periodic captures. The capture rate is specified in milliHertz
+    // and the capture format is according to flags  (see callback_flags).
+    status_t setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate);
+
+    // set the capture size capture size must be a power of two in the range
+    // [VISUALIZER_CAPTURE_SIZE_MAX. VISUALIZER_CAPTURE_SIZE_MIN]
+    // must be called when the visualizer is not enabled
+    status_t setCaptureSize(uint32_t size);
+    uint32_t getCaptureSize() { return mCaptureSize; }
+
+    // returns the capture rate indicated when installing the callback
+    uint32_t getCaptureRate() { return mCaptureRate; }
+
+    // returns the sampling rate of the audio being captured
+    uint32_t getSamplingRate() { return mSampleRate; }
+
+    // set the way volume affects the captured data
+    // mode must one of VISUALIZER_SCALING_MODE_NORMALIZED,
+    //  VISUALIZER_SCALING_MODE_AS_PLAYED
+    status_t setScalingMode(uint32_t mode);
+    uint32_t getScalingMode() { return mScalingMode; }
+
+    // set which measurements are done on the audio buffers processed by the effect.
+    // valid measurements (mask): MEASUREMENT_MODE_PEAK_RMS
+    status_t setMeasurementMode(uint32_t mode);
+    uint32_t getMeasurementMode() { return mMeasurementMode; }
+
+    // return a set of int32_t measurements
+    status_t getIntMeasurements(uint32_t type, uint32_t number, int32_t *measurements);
+
+    // return a capture in PCM 8 bit unsigned format. The size of the capture is equal to
+    // getCaptureSize()
+    status_t getWaveForm(uint8_t *waveform);
+
+    // return a capture in FFT 8 bit signed format. The size of the capture is equal to
+    // getCaptureSize() but the length of the FFT is half of the size (both parts of the spectrum
+    // are returned
+    status_t getFft(uint8_t *fft);
+    void release();
+
+protected:
+    // from IEffectClient
+    virtual void controlStatusChanged(bool controlGranted);
+
+private:
+
+    static const uint32_t CAPTURE_RATE_MAX = 20000;
+    static const uint32_t CAPTURE_RATE_DEF = 10000;
+    static const uint32_t CAPTURE_SIZE_DEF = VISUALIZER_CAPTURE_SIZE_MAX;
+
+    /* internal class to handle the callback */
+    class CaptureThread : public Thread
+    {
+    public:
+        CaptureThread(Visualizer* visualizer, uint32_t captureRate, bool bCanCallJava = false);
+
+    private:
+        friend class Visualizer;
+        virtual bool        threadLoop();
+        wp<Visualizer> mReceiver;
+        Mutex       mLock;
+        uint32_t mSleepTimeUs;
+    };
+
+    status_t doFft(uint8_t *fft, uint8_t *waveform);
+    void periodicCapture();
+    uint32_t initCaptureSize();
+
+    Mutex mCaptureLock;
+    uint32_t mCaptureRate;
+    uint32_t mCaptureSize;
+    uint32_t mSampleRate;
+    uint32_t mScalingMode;
+    uint32_t mMeasurementMode;
+    capture_cbk_t mCaptureCallBack;
+    void *mCaptureCbkUser;
+    sp<CaptureThread> mCaptureThread;
+    uint32_t mCaptureFlags;
+};
+
+
+}; // namespace android
+
+#endif // ANDROID_MEDIA_VISUALIZER_H
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index 45de36e..1362433 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -24,7 +24,7 @@
 #include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/threads.h>
-#include "media/Visualizer.h"
+#include "Visualizer.h"
 
 #include <nativehelper/ScopedUtfChars.h>
 
diff --git a/media/jni/audioeffect/exports.lds b/media/jni/audioeffect/exports.lds
new file mode 100644
index 0000000..70491f4
--- /dev/null
+++ b/media/jni/audioeffect/exports.lds
@@ -0,0 +1,6 @@
+{
+    global:
+        *;
+    local:
+        *android10Visualizer*;
+};
diff --git a/media/jni/soundpool/Android.bp b/media/jni/soundpool/Android.bp
index 35b7b01..0be2514 100644
--- a/media/jni/soundpool/Android.bp
+++ b/media/jni/soundpool/Android.bp
@@ -3,11 +3,20 @@
 
     srcs: [
         "android_media_SoundPool.cpp",
+        "Sound.cpp",
+        "SoundDecoder.cpp",
+        "SoundManager.cpp",
         "SoundPool.cpp",
-        "SoundPoolThread.cpp",
+        "Stream.cpp",
+        "StreamManager.cpp",
+    ],
+
+    header_libs: [
+        "libmedia_headers",
     ],
 
     shared_libs: [
+        "libaudioutils",
         "liblog",
         "libcutils",
         "libutils",
diff --git a/media/jni/soundpool/Sound.cpp b/media/jni/soundpool/Sound.cpp
new file mode 100644
index 0000000..0bbc3e4
--- /dev/null
+++ b/media/jni/soundpool/Sound.cpp
@@ -0,0 +1,241 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoundPool::Sound"
+#include <utils/Log.h>
+
+#include "Sound.h"
+
+#include <media/NdkMediaCodec.h>
+#include <media/NdkMediaExtractor.h>
+#include <media/NdkMediaFormat.h>
+
+namespace android::soundpool {
+
+constexpr uint32_t kMaxSampleRate = 192000;
+constexpr size_t   kDefaultHeapSize = 1024 * 1024; // 1MB (compatible with low mem devices)
+
+Sound::Sound(int32_t soundID, int fd, int64_t offset, int64_t length)
+    : mSoundID(soundID)
+    , mFd(dup(fd))
+    , mOffset(offset)
+    , mLength(length)
+{
+    ALOGV("%s(soundID=%d, fd=%d, offset=%lld, length=%lld)",
+            __func__, soundID, fd, (long long)offset, (long long)length);
+    ALOGW_IF(mFd == -1, "Unable to dup descriptor %d", fd);
+}
+
+Sound::~Sound()
+{
+    ALOGV("%s(soundID=%d, fd=%d)", __func__, mSoundID, mFd.get());
+}
+
+static status_t decode(int fd, int64_t offset, int64_t length,
+        uint32_t *rate, int32_t *channelCount, audio_format_t *audioFormat,
+        audio_channel_mask_t *channelMask, sp<MemoryHeapBase> heap,
+        size_t *sizeInBytes) {
+    ALOGV("%s(fd=%d, offset=%lld, length=%lld, ...)",
+            __func__, fd, (long long)offset, (long long)length);
+    std::unique_ptr<AMediaExtractor, decltype(&AMediaExtractor_delete)> ex{
+            AMediaExtractor_new(), &AMediaExtractor_delete};
+    status_t err = AMediaExtractor_setDataSourceFd(ex.get(), fd, offset, length);
+
+    if (err != AMEDIA_OK) {
+        return err;
+    }
+
+    *audioFormat = AUDIO_FORMAT_PCM_16_BIT;  // default format for audio codecs.
+    const size_t numTracks = AMediaExtractor_getTrackCount(ex.get());
+    for (size_t i = 0; i < numTracks; i++) {
+        std::unique_ptr<AMediaFormat, decltype(&AMediaFormat_delete)> format{
+                AMediaExtractor_getTrackFormat(ex.get(), i), &AMediaFormat_delete};
+        const char *mime;
+        if (!AMediaFormat_getString(format.get(),  AMEDIAFORMAT_KEY_MIME, &mime)) {
+            return UNKNOWN_ERROR;
+        }
+        if (strncmp(mime, "audio/", 6) == 0) {
+            std::unique_ptr<AMediaCodec, decltype(&AMediaCodec_delete)> codec{
+                    AMediaCodec_createDecoderByType(mime), &AMediaCodec_delete};
+            if (codec == nullptr
+                    || AMediaCodec_configure(codec.get(), format.get(),
+                            nullptr /* window */, nullptr /* drm */, 0 /* flags */) != AMEDIA_OK
+                    || AMediaCodec_start(codec.get()) != AMEDIA_OK
+                    || AMediaExtractor_selectTrack(ex.get(), i) != AMEDIA_OK) {
+                return UNKNOWN_ERROR;
+            }
+
+            bool sawInputEOS = false;
+            bool sawOutputEOS = false;
+            uint8_t* writePos = static_cast<uint8_t*>(heap->getBase());
+            size_t available = heap->getSize();
+            size_t written = 0;
+            format.reset(AMediaCodec_getOutputFormat(codec.get())); // update format.
+
+            while (!sawOutputEOS) {
+                if (!sawInputEOS) {
+                    ssize_t bufidx = AMediaCodec_dequeueInputBuffer(codec.get(), 5000);
+                    ALOGV("%s: input buffer %zd", __func__, bufidx);
+                    if (bufidx >= 0) {
+                        size_t bufsize;
+                        uint8_t * const buf = AMediaCodec_getInputBuffer(
+                                codec.get(), bufidx, &bufsize);
+                        if (buf == nullptr) {
+                            ALOGE("%s: AMediaCodec_getInputBuffer returned nullptr, short decode",
+                                    __func__);
+                            break;
+                        }
+                        int sampleSize = AMediaExtractor_readSampleData(ex.get(), buf, bufsize);
+                        ALOGV("%s: read %d", __func__, sampleSize);
+                        if (sampleSize < 0) {
+                            sampleSize = 0;
+                            sawInputEOS = true;
+                            ALOGV("%s: EOS", __func__);
+                        }
+                        const int64_t presentationTimeUs = AMediaExtractor_getSampleTime(ex.get());
+
+                        const media_status_t mstatus = AMediaCodec_queueInputBuffer(
+                                codec.get(), bufidx,
+                                0 /* offset */, sampleSize, presentationTimeUs,
+                                sawInputEOS ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
+                        if (mstatus != AMEDIA_OK) {
+                            // AMEDIA_ERROR_UNKNOWN == { -ERANGE -EINVAL -EACCES }
+                            ALOGE("%s: AMediaCodec_queueInputBuffer returned status %d,"
+                                    "short decode",
+                                    __func__, (int)mstatus);
+                            break;
+                        }
+                        (void)AMediaExtractor_advance(ex.get());
+                    }
+                }
+
+                AMediaCodecBufferInfo info;
+                const int status = AMediaCodec_dequeueOutputBuffer(codec.get(), &info, 1);
+                ALOGV("%s: dequeueoutput returned: %d", __func__, status);
+                if (status >= 0) {
+                    if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
+                        ALOGV("%s: output EOS", __func__);
+                        sawOutputEOS = true;
+                    }
+                    ALOGV("%s: got decoded buffer size %d", __func__, info.size);
+
+                    const uint8_t * const buf = AMediaCodec_getOutputBuffer(
+                            codec.get(), status, nullptr /* out_size */);
+                    if (buf == nullptr) {
+                        ALOGE("%s: AMediaCodec_getOutputBuffer returned nullptr, short decode",
+                                __func__);
+                        break;
+                    }
+                    const size_t dataSize = std::min((size_t)info.size, available);
+                    memcpy(writePos, buf + info.offset, dataSize);
+                    writePos += dataSize;
+                    written += dataSize;
+                    available -= dataSize;
+                    const media_status_t mstatus = AMediaCodec_releaseOutputBuffer(
+                            codec.get(), status, false /* render */);
+                    if (mstatus != AMEDIA_OK) {
+                        // AMEDIA_ERROR_UNKNOWN == { -ERANGE -EINVAL -EACCES }
+                        ALOGE("%s: AMediaCodec_releaseOutputBuffer"
+                                " returned status %d, short decode",
+                                __func__, (int)mstatus);
+                        break;
+                    }
+                    if (available == 0) {
+                        // there might be more data, but there's no space for it
+                        sawOutputEOS = true;
+                    }
+                } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
+                    ALOGV("%s: output buffers changed", __func__);
+                } else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
+                    format.reset(AMediaCodec_getOutputFormat(codec.get())); // update format
+                    ALOGV("%s: format changed to: %s",
+                           __func__, AMediaFormat_toString(format.get()));
+                } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
+                    ALOGV("%s: no output buffer right now", __func__);
+                } else if (status <= AMEDIA_ERROR_BASE) {
+                    ALOGE("%s: decode error: %d", __func__, status);
+                    break;
+                } else {
+                    ALOGV("%s: unexpected info code: %d", __func__, status);
+                }
+            }
+
+            (void)AMediaCodec_stop(codec.get());
+            if (!AMediaFormat_getInt32(
+                    format.get(), AMEDIAFORMAT_KEY_SAMPLE_RATE, (int32_t*) rate) ||
+                !AMediaFormat_getInt32(
+                    format.get(), AMEDIAFORMAT_KEY_CHANNEL_COUNT, channelCount)) {
+                return UNKNOWN_ERROR;
+            }
+            if (!AMediaFormat_getInt32(format.get(), AMEDIAFORMAT_KEY_CHANNEL_MASK,
+                    (int32_t*) channelMask)) {
+                *channelMask = AUDIO_CHANNEL_NONE;
+            }
+            *sizeInBytes = written;
+            return OK;
+        }
+    }
+    return UNKNOWN_ERROR;
+}
+
+status_t Sound::doLoad()
+{
+    ALOGV("%s()", __func__);
+    status_t status = NO_INIT;
+    if (mFd.get() != -1) {
+        mHeap = new MemoryHeapBase(kDefaultHeapSize);
+
+        ALOGV("%s: start decode", __func__);
+        uint32_t sampleRate;
+        int32_t channelCount;
+        audio_format_t format;
+        audio_channel_mask_t channelMask;
+        status_t status = decode(mFd.get(), mOffset, mLength, &sampleRate, &channelCount, &format,
+                        &channelMask, mHeap, &mSizeInBytes);
+        ALOGV("%s: close(%d)", __func__, mFd.get());
+        mFd.reset();  // close
+
+        if (status != NO_ERROR) {
+            ALOGE("%s: unable to load sound", __func__);
+        } else if (sampleRate > kMaxSampleRate) {
+            ALOGE("%s: sample rate (%u) out of range", __func__, sampleRate);
+            status = BAD_VALUE;
+        } else if (channelCount < 1 || channelCount > FCC_8) {
+            ALOGE("%s: sample channel count (%d) out of range", __func__, channelCount);
+            status = BAD_VALUE;
+        } else {
+            // Correctly loaded, proper parameters
+            ALOGV("%s: pointer = %p, sizeInBytes = %zu, sampleRate = %u, channelCount = %d",
+                  __func__, mHeap->getBase(), mSizeInBytes, sampleRate, channelCount);
+            mData = new MemoryBase(mHeap, 0, mSizeInBytes);
+            mSampleRate = sampleRate;
+            mChannelCount = channelCount;
+            mFormat = format;
+            mChannelMask = channelMask;
+            mState = READY;  // this should be last, as it is an atomic sync point
+            return NO_ERROR;
+        }
+    } else {
+        ALOGE("%s: uninitialized fd, dup failed", __func__);
+    }
+    // ERROR handling
+    mHeap.clear();
+    mState = DECODE_ERROR; // this should be last, as it is an atomic sync point
+    return status;
+}
+
+} // namespace android::soundpool
diff --git a/media/jni/soundpool/Sound.h b/media/jni/soundpool/Sound.h
new file mode 100644
index 0000000..efe940a
--- /dev/null
+++ b/media/jni/soundpool/Sound.h
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
+#include <system/audio.h>
+
+namespace android::soundpool {
+
+class SoundDecoder;
+
+/**
+ * Sound is a resource used by SoundPool, referenced by soundID.
+ *
+ * After loading, it is effectively const so no locking required.
+ * However, in order to guarantee that all the values have been
+ * written properly and read properly, we use the mState as an atomic synchronization
+ * point.  So if getState() shows READY, then all the other getters may
+ * be safely read.
+ *
+ * Technical details:
+ * We access the mState atomic value through memory_order_seq_cst
+ *
+ * https://en.cppreference.com/w/cpp/atomic/memory_order
+ *
+ * which provides memory barriers.  So if the last value written by the SoundDecoder
+ * is mState, then the compiler ensures no other prior writes by SoundDecoder will be
+ * reordered afterwards, and memory barrier is placed (as necessary) to ensure the
+ * cache is visible to other processors.
+ *
+ * Likewise, if the first value read by SoundPool is mState,
+ * the compiler ensures no reads for that thread will be reordered before mState is read,
+ * and a memory barrier is placed (as necessary) to ensure that the cache is properly
+ * updated with other processor's writes before reading.
+ *
+ * See https://developer.android.com/training/articles/smp for discussions about
+ * the variant load-acquire, store-release semantics.
+ */
+class Sound {
+    friend SoundDecoder;  // calls doLoad().
+
+public:
+    enum sound_state : int32_t { LOADING, READY, DECODE_ERROR };
+    // A sound starts in the LOADING state and transitions only once
+    // to either READY or DECODE_ERROR when doLoad() is called.
+
+    Sound(int soundID, int fd, int64_t offset, int64_t length);
+    ~Sound();
+
+    int32_t getSoundID() const { return mSoundID; }
+    int32_t getChannelCount() const { return mChannelCount; }
+    uint32_t getSampleRate() const { return mSampleRate; }
+    audio_format_t getFormat() const { return mFormat; }
+    audio_channel_mask_t getChannelMask() const { return mChannelMask; }
+    size_t getSizeInBytes() const { return mSizeInBytes; }
+    sound_state getState() const { return mState; }
+    uint8_t* getData() const { return static_cast<uint8_t*>(mData->unsecurePointer()); }
+    sp<IMemory> getIMemory() const { return mData; }
+
+private:
+    status_t doLoad();  // only SoundDecoder accesses this.
+
+    size_t               mSizeInBytes = 0;
+    const int32_t        mSoundID;
+    uint32_t             mSampleRate = 0;
+    std::atomic<sound_state> mState = LOADING; // used as synchronization point
+    int32_t              mChannelCount = 0;
+    audio_format_t       mFormat = AUDIO_FORMAT_INVALID;
+    audio_channel_mask_t mChannelMask = AUDIO_CHANNEL_NONE;
+    base::unique_fd      mFd;     // initialized in constructor, reset to -1 after loading
+    const int64_t        mOffset; // int64_t to match java long, see off64_t
+    const int64_t        mLength; // int64_t to match java long, see off64_t
+    sp<IMemory>          mData;
+    sp<MemoryHeapBase>   mHeap;
+};
+
+} // namespace android::soundpool
diff --git a/media/jni/soundpool/SoundDecoder.cpp b/media/jni/soundpool/SoundDecoder.cpp
new file mode 100644
index 0000000..12200ef
--- /dev/null
+++ b/media/jni/soundpool/SoundDecoder.cpp
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoundPool::SoundDecoder"
+#include "utils/Log.h"
+
+#include "SoundDecoder.h"
+
+namespace android::soundpool {
+
+// Maximum Samples that can be background decoded before we block the caller.
+static constexpr size_t kMaxQueueSize = 128;
+
+// The amount of time we wait for a new Sound decode request
+// before the SoundDecoder thread closes.
+static constexpr int32_t kWaitTimeBeforeCloseMs = 1000;
+
+SoundDecoder::SoundDecoder(SoundManager* soundManager, size_t threads)
+    : mSoundManager(soundManager)
+{
+    ALOGV("%s(%p, %zu)", __func__, soundManager, threads);
+    // ThreadPool is created, but we don't launch any threads.
+    mThreadPool = std::make_unique<ThreadPool>(
+            std::min(threads, (size_t)std::thread::hardware_concurrency()),
+            "SoundDecoder_");
+}
+
+SoundDecoder::~SoundDecoder()
+{
+    ALOGV("%s()", __func__);
+    quit();
+}
+
+void SoundDecoder::quit()
+{
+    ALOGV("%s()", __func__);
+    {
+        std::lock_guard lock(mLock);
+        mQuit = true;
+        mQueueSpaceAvailable.notify_all(); // notify all load waiters
+        mQueueDataAvailable.notify_all();  // notify all worker threads
+    }
+    mThreadPool->quit();
+}
+
+void SoundDecoder::run(int32_t id __unused /* ALOGV only */)
+{
+    ALOGV("%s(%d): entering", __func__, id);
+    std::unique_lock lock(mLock);
+    while (!mQuit) {
+        if (mSoundIDs.size() == 0) {
+            ALOGV("%s(%d): waiting", __func__, id);
+            mQueueDataAvailable.wait_for(
+                    lock, std::chrono::duration<int32_t, std::milli>(kWaitTimeBeforeCloseMs));
+            if (mSoundIDs.size() == 0) {
+                break; // no new sound, exit this thread.
+            }
+            continue;
+        }
+        const int32_t soundID = mSoundIDs.front();
+        mSoundIDs.pop_front();
+        mQueueSpaceAvailable.notify_one();
+        ALOGV("%s(%d): processing soundID: %d  size: %zu", __func__, id, soundID, mSoundIDs.size());
+        lock.unlock();
+        std::shared_ptr<Sound> sound = mSoundManager->findSound(soundID);
+        status_t status = NO_INIT;
+        if (sound.get() != nullptr) {
+            status = sound->doLoad();
+        }
+        ALOGV("%s(%d): notifying loaded soundID:%d  status:%d", __func__, id, soundID, status);
+        mSoundManager->notify(SoundPoolEvent(SoundPoolEvent::SOUND_LOADED, soundID, status));
+        lock.lock();
+    }
+    ALOGV("%s(%d): exiting", __func__, id);
+}
+
+void SoundDecoder::loadSound(int32_t soundID)
+{
+    ALOGV("%s(%d)", __func__, soundID);
+    size_t pendingSounds;
+    {
+        std::unique_lock lock(mLock);
+        while (mSoundIDs.size() == kMaxQueueSize) {
+            if (mQuit) return;
+            ALOGV("%s: waiting soundID: %d size: %zu", __func__, soundID, mSoundIDs.size());
+            mQueueSpaceAvailable.wait(lock);
+        }
+        if (mQuit) return;
+        mSoundIDs.push_back(soundID);
+        mQueueDataAvailable.notify_one();
+        ALOGV("%s: adding soundID: %d  size: %zu", __func__, soundID, mSoundIDs.size());
+        pendingSounds = mSoundIDs.size();
+    }
+    // Launch threads as needed.  The "as needed" is weakly consistent as we release mLock.
+    if (pendingSounds > mThreadPool->getActiveThreadCount()) {
+        const int32_t id __unused = mThreadPool->launch([this](int32_t id) { run(id); });
+        ALOGV_IF(id != 0, "%s: launched thread %d", __func__, id);
+    }
+}
+
+} // end namespace android::soundpool
diff --git a/media/jni/soundpool/SoundDecoder.h b/media/jni/soundpool/SoundDecoder.h
new file mode 100644
index 0000000..1288943
--- /dev/null
+++ b/media/jni/soundpool/SoundDecoder.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "SoundPool.h"
+
+#include <deque>
+#include <mutex>
+
+namespace android::soundpool {
+
+/**
+ * SoundDecoder handles background decoding tasks.
+ */
+class SoundDecoder {
+public:
+    SoundDecoder(SoundManager* soundManager, size_t threads);
+    ~SoundDecoder();
+    void loadSound(int32_t soundID);
+    void quit();
+
+private:
+    void run(int32_t id);                       // The decode thread function.
+
+    SoundManager* const     mSoundManager;      // set in constructor, has own lock
+    std::unique_ptr<ThreadPool> mThreadPool;    // set in constructor, has own lock
+
+    std::mutex              mLock;
+    std::condition_variable mQueueSpaceAvailable;
+    std::condition_variable mQueueDataAvailable;
+
+    std::deque<int32_t>     mSoundIDs;            // GUARDED_BY(mLock);
+    bool                    mQuit = false;        // GUARDED_BY(mLock);
+};
+
+} // end namespace android::soundpool
+
diff --git a/media/jni/soundpool/SoundManager.cpp b/media/jni/soundpool/SoundManager.cpp
new file mode 100644
index 0000000..3c625bf
--- /dev/null
+++ b/media/jni/soundpool/SoundManager.cpp
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoundPool::SoundManager"
+#include <utils/Log.h>
+
+#include "SoundManager.h"
+
+#include <thread>
+
+#include "SoundDecoder.h"
+
+namespace android::soundpool {
+
+static const size_t kDecoderThreads = std::thread::hardware_concurrency() >= 4 ? 2 : 1;
+
+SoundManager::SoundManager()
+    : mDecoder{std::make_unique<SoundDecoder>(this, kDecoderThreads)}
+{
+    ALOGV("%s()", __func__);
+}
+
+SoundManager::~SoundManager()
+{
+    ALOGV("%s()", __func__);
+    mDecoder->quit();
+
+    std::lock_guard lock(mSoundManagerLock);
+    mSounds.clear();
+}
+
+int32_t SoundManager::load(int fd, int64_t offset, int64_t length, int32_t priority __unused)
+{
+    ALOGV("%s(fd=%d, offset=%lld, length=%lld, priority=%d)",
+            __func__, fd, (long long)offset, (long long)length, priority);
+    int32_t soundID;
+    {
+        std::lock_guard lock(mSoundManagerLock);
+        // mNextSoundID is always positive and does not "integer overflow"
+        do {
+            mNextSoundID = mNextSoundID == INT32_MAX ? 1 : mNextSoundID + 1;
+        } while (findSound_l(mNextSoundID) != nullptr);
+        soundID = mNextSoundID;
+        auto sound = std::make_shared<Sound>(soundID, fd, offset, length);
+        mSounds.emplace(soundID, sound);
+    }
+    // mDecoder->loadSound() must be called outside of mSoundManagerLock.
+    // mDecoder->loadSound() may block on mDecoder message queue space;
+    // the message queue emptying may block on SoundManager::findSound().
+    //
+    // It is theoretically possible that sound loads might decode out-of-order.
+    mDecoder->loadSound(soundID);
+    return soundID;
+}
+
+bool SoundManager::unload(int32_t soundID)
+{
+    ALOGV("%s(soundID=%d)", __func__, soundID);
+    std::lock_guard lock(mSoundManagerLock);
+    return mSounds.erase(soundID) > 0; // erase() returns number of sounds removed.
+}
+
+std::shared_ptr<Sound> SoundManager::findSound(int32_t soundID) const
+{
+    std::lock_guard lock(mSoundManagerLock);
+    return findSound_l(soundID);
+}
+
+std::shared_ptr<Sound> SoundManager::findSound_l(int32_t soundID) const
+{
+    auto it = mSounds.find(soundID);
+    return it != mSounds.end() ? it->second : nullptr;
+}
+
+void SoundManager::setCallback(SoundPool *soundPool, SoundPoolCallback* callback, void* user)
+{
+    mCallbackHandler.setCallback(soundPool, callback, user);
+}
+
+void SoundManager::notify(SoundPoolEvent event)
+{
+    mCallbackHandler.notify(event);
+}
+
+void* SoundManager::getUserData() const
+{
+    return mCallbackHandler.getUserData();
+}
+
+} // namespace android::soundpool
diff --git a/media/jni/soundpool/SoundManager.h b/media/jni/soundpool/SoundManager.h
new file mode 100644
index 0000000..9201e78
--- /dev/null
+++ b/media/jni/soundpool/SoundManager.h
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "Sound.h"
+
+#include <mutex>
+#include <unordered_map>
+
+namespace android {
+
+class SoundPool;
+
+// for queued events
+class SoundPoolEvent {
+public:
+    explicit SoundPoolEvent(int msg, int arg1 = 0, int arg2 = 0) :
+        mMsg(msg), mArg1(arg1), mArg2(arg2) {}
+    const int mMsg;   // MessageType
+    const int mArg1;  // soundID
+    const int mArg2;  // status
+    enum MessageType { INVALID, SOUND_LOADED };
+};
+
+// callback function prototype
+typedef void SoundPoolCallback(SoundPoolEvent event, SoundPool* soundPool, void* user);
+
+} // namespace android
+
+namespace android::soundpool {
+
+// This class manages Sounds for the SoundPool.
+class SoundManager {
+public:
+    SoundManager();
+    ~SoundManager();
+
+    // Matches corresponding SoundPool API functions
+    int32_t load(int fd, int64_t offset, int64_t length, int32_t priority);
+    bool unload(int32_t soundID);
+    void setCallback(SoundPool* soundPool, SoundPoolCallback* callback, void* user);
+    void* getUserData() const;
+
+    // SoundPool and SoundDecoder access
+    std::shared_ptr<Sound> findSound(int32_t soundID) const;
+
+    // from the SoundDecoder
+    void notify(SoundPoolEvent event);
+
+private:
+
+    // CallbackHandler is used to manage notifications back to the app when a sound
+    // has been loaded.  It uses a recursive lock to allow setting the callback
+    // during the callback.
+    class CallbackHandler {
+    public:
+        void setCallback(SoundPool *soundPool, SoundPoolCallback* callback, void* userData)
+        {
+            std::lock_guard<std::recursive_mutex> lock(mCallbackLock);
+            mSoundPool = soundPool;
+            mCallback = callback;
+            mUserData = userData;
+        }
+        void notify(SoundPoolEvent event) const
+        {
+            std::lock_guard<std::recursive_mutex> lock(mCallbackLock);
+            if (mCallback != nullptr) {
+                mCallback(event, mSoundPool, mUserData);
+                // Note: mCallback may call setCallback().
+                // so mCallback, mUserData may have changed.
+            }
+        }
+        void* getUserData() const
+        {
+            std::lock_guard<std::recursive_mutex> lock(mCallbackLock);
+            return mUserData;
+        }
+    private:
+        mutable std::recursive_mutex  mCallbackLock; // allow mCallback to setCallback().
+        SoundPool*          mSoundPool = nullptr; // GUARDED_BY(mCallbackLock)
+        SoundPoolCallback*  mCallback = nullptr;  // GUARDED_BY(mCallbackLock)
+        void*               mUserData = nullptr;  // GUARDED_BY(mCallbackLock)
+    };
+
+    std::shared_ptr<Sound> findSound_l(int32_t soundID) const;
+
+    // The following variables are initialized in constructor and can be accessed anytime.
+    CallbackHandler         mCallbackHandler;              // has its own lock
+    const std::unique_ptr<SoundDecoder> mDecoder;          // has its own lock
+
+    mutable std::mutex      mSoundManagerLock;
+    std::unordered_map<int, std::shared_ptr<Sound>> mSounds; // GUARDED_BY(mSoundManagerLock)
+    int32_t                 mNextSoundID = 0;    // GUARDED_BY(mSoundManagerLock)
+};
+
+} // namespace android::soundpool
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 102bbf0..ac44843 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -16,1124 +16,230 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "SoundPool"
-
-#include <chrono>
-#include <inttypes.h>
-#include <thread>
 #include <utils/Log.h>
 
-#define USE_SHARED_MEM_BUFFER
+#include <algorithm>
+#include <thread>
 
-#include <media/AudioTrack.h>
 #include "SoundPool.h"
-#include "SoundPoolThread.h"
-#include <media/NdkMediaCodec.h>
-#include <media/NdkMediaExtractor.h>
-#include <media/NdkMediaFormat.h>
 
 namespace android
 {
 
-int kDefaultBufferCount = 4;
-uint32_t kMaxSampleRate = 48000;
-uint32_t kDefaultSampleRate = 44100;
-uint32_t kDefaultFrameCount = 1200;
-size_t kDefaultHeapSize = 1024 * 1024; // 1MB
+// kManagerThreads = 1 historically.
+// Not really necessary to have more than one, but it does speed things up by about
+// 25% having 2 threads instead of 1 when playing many sounds.  Having many threads
+// could starve other AudioFlinger clients with SoundPool activity. It may also cause
+// issues with app loading, e.g. Camera.
+static const size_t kStreamManagerThreads = std::thread::hardware_concurrency() >= 4 ? 2 : 1;
 
+// kUseApiLock = true prior to R.
+// Set to true to prevent multiple users access internal to the SoundPool API.
+// Set to false to make the SoundPool methods weakly consistent.  When set to false,
+// only AutoPause and AutoResume are locked, which are the only two methods that
+// require API level locking for consistency.
+static constexpr bool kUseApiLock = false;
 
-SoundPool::SoundPool(int maxChannels, const audio_attributes_t* pAttributes)
+namespace {
+// Check input arguments to SoundPool - return "true" to reject request.
+
+bool checkVolume(float *leftVolume, float *rightVolume)
 {
-    ALOGV("SoundPool constructor: maxChannels=%d, attr.usage=%d, attr.flags=0x%x, attr.tags=%s",
-            maxChannels, pAttributes->usage, pAttributes->flags, pAttributes->tags);
-
-    // check limits
-    mMaxChannels = maxChannels;
-    if (mMaxChannels < 1) {
-        mMaxChannels = 1;
+    if (*leftVolume != std::clamp(*leftVolume, 0.f, 1.f) ||
+            *rightVolume != std::clamp(*rightVolume, 0.f, 1.f)) {
+        ALOGI("volume l=%f r=%f out of (0.f, 1.f) bounds, using 1.f", *leftVolume, *rightVolume);
+        // for backward compatibility use 1.f.
+        *leftVolume = *rightVolume = 1.f;
     }
-    else if (mMaxChannels > 32) {
-        mMaxChannels = 32;
+    return false;
+}
+
+bool checkRate(float *rate)
+{
+    if (*rate != std::clamp(*rate, 0.125f, 8.f)) {
+        ALOGI("rate %f out of (0.125f, 8.f) bounds, clamping", *rate);
+        // for backward compatibility just clamp
+        *rate = std::clamp(*rate, 0.125f, 8.f);
     }
-    ALOGW_IF(maxChannels != mMaxChannels, "App requested %d channels", maxChannels);
+    return false;
+}
 
-    mQuit = false;
-    mMuted = false;
-    mDecodeThread = 0;
-    memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t));
-    mAllocated = 0;
-    mNextSampleID = 0;
-    mNextChannelID = 0;
-
-    mCallback = 0;
-    mUserData = 0;
-
-    mChannelPool = new SoundChannel[mMaxChannels];
-    for (int i = 0; i < mMaxChannels; ++i) {
-        mChannelPool[i].init(this);
-        mChannels.push_back(&mChannelPool[i]);
+bool checkPriority(int32_t *priority)
+{
+    if (*priority < 0) {
+        ALOGI("negative priority %d, should be >= 0.", *priority);
+        // for backward compatibility, ignore.
     }
+    return false;
+}
 
-    // start decode thread
-    startThreads();
+bool checkLoop(int32_t *loop)
+{
+    if (*loop < -1) {
+        ALOGI("loop %d, should be >= -1", *loop);
+        *loop = -1;
+    }
+    return false;
+}
+
+} // namespace
+
+SoundPool::SoundPool(int32_t maxStreams, const audio_attributes_t* attributes)
+    : mStreamManager(maxStreams, kStreamManagerThreads, attributes)
+{
+    ALOGV("%s(maxStreams=%d, attr={ content_type=%d, usage=%d, flags=0x%x, tags=%s })",
+            __func__, maxStreams,
+            attributes->content_type, attributes->usage, attributes->flags, attributes->tags);
 }
 
 SoundPool::~SoundPool()
 {
-    ALOGV("SoundPool destructor");
-    mDecodeThread->quit();
-    quit();
-
-    Mutex::Autolock lock(&mLock);
-
-    mChannels.clear();
-    if (mChannelPool)
-        delete [] mChannelPool;
-    // clean up samples
-    ALOGV("clear samples");
-    mSamples.clear();
-
-    if (mDecodeThread)
-        delete mDecodeThread;
+    ALOGV("%s()", __func__);
 }
 
-void SoundPool::addToRestartList(SoundChannel* channel)
+int32_t SoundPool::load(int fd, int64_t offset, int64_t length, int32_t priority)
 {
-    Mutex::Autolock lock(&mRestartLock);
-    if (!mQuit) {
-        mRestart.push_back(channel);
-        mCondition.signal();
-    }
+    ALOGV("%s(fd=%d, offset=%lld, length=%lld, priority=%d)",
+            __func__, fd, (long long)offset, (long long)length, priority);
+    auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
+    return mSoundManager.load(fd, offset, length, priority);
 }
 
-void SoundPool::addToStopList(SoundChannel* channel)
+bool SoundPool::unload(int32_t soundID)
 {
-    Mutex::Autolock lock(&mRestartLock);
-    if (!mQuit) {
-        mStop.push_back(channel);
-        mCondition.signal();
-    }
+    ALOGV("%s(%d)", __func__, soundID);
+    auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
+    return mSoundManager.unload(soundID);
 }
 
-int SoundPool::beginThread(void* arg)
+int32_t SoundPool::play(int32_t soundID, float leftVolume, float rightVolume,
+        int32_t priority, int32_t loop, float rate)
 {
-    SoundPool* p = (SoundPool*)arg;
-    return p->run();
-}
+    ALOGV("%s(soundID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f)",
+            __func__, soundID, leftVolume, rightVolume, priority, loop, rate);
 
-int SoundPool::run()
-{
-    mRestartLock.lock();
-    while (!mQuit) {
-        mCondition.wait(mRestartLock);
-        ALOGV("awake");
-        if (mQuit) break;
+    // New for R: check arguments to ensure track can be created.
+    // If SoundPool defers the creation of the AudioTrack to the StreamManager thread,
+    // the failure to create may not be visible to the caller, so this precheck is needed.
+    if (checkVolume(&leftVolume, &rightVolume)
+            || checkPriority(&priority)
+            || checkLoop(&loop)
+            || checkRate(&rate)) return 0;
 
-        while (!mStop.empty()) {
-            SoundChannel* channel;
-            ALOGV("Getting channel from stop list");
-            List<SoundChannel* >::iterator iter = mStop.begin();
-            channel = *iter;
-            mStop.erase(iter);
-            mRestartLock.unlock();
-            if (channel != 0) {
-                Mutex::Autolock lock(&mLock);
-                channel->stop();
-            }
-            mRestartLock.lock();
-            if (mQuit) break;
-        }
-
-        while (!mRestart.empty()) {
-            SoundChannel* channel;
-            ALOGV("Getting channel from list");
-            List<SoundChannel*>::iterator iter = mRestart.begin();
-            channel = *iter;
-            mRestart.erase(iter);
-            mRestartLock.unlock();
-            if (channel != 0) {
-                Mutex::Autolock lock(&mLock);
-                channel->nextEvent();
-            }
-            mRestartLock.lock();
-            if (mQuit) break;
-        }
-    }
-
-    mStop.clear();
-    mRestart.clear();
-    mCondition.signal();
-    mRestartLock.unlock();
-    ALOGV("goodbye");
-    return 0;
-}
-
-void SoundPool::quit()
-{
-    mRestartLock.lock();
-    mQuit = true;
-    mCondition.signal();
-    mCondition.wait(mRestartLock);
-    ALOGV("return from quit");
-    mRestartLock.unlock();
-}
-
-bool SoundPool::startThreads()
-{
-    createThreadEtc(beginThread, this, "SoundPool");
-    if (mDecodeThread == NULL)
-        mDecodeThread = new SoundPoolThread(this);
-    return mDecodeThread != NULL;
-}
-
-sp<Sample> SoundPool::findSample(int sampleID)
-{
-    Mutex::Autolock lock(&mLock);
-    return findSample_l(sampleID);
-}
-
-sp<Sample> SoundPool::findSample_l(int sampleID)
-{
-    return mSamples.valueFor(sampleID);
-}
-
-SoundChannel* SoundPool::findChannel(int channelID)
-{
-    for (int i = 0; i < mMaxChannels; ++i) {
-        if (mChannelPool[i].channelID() == channelID) {
-            return &mChannelPool[i];
-        }
-    }
-    return NULL;
-}
-
-SoundChannel* SoundPool::findNextChannel(int channelID)
-{
-    for (int i = 0; i < mMaxChannels; ++i) {
-        if (mChannelPool[i].nextChannelID() == channelID) {
-            return &mChannelPool[i];
-        }
-    }
-    return NULL;
-}
-
-int SoundPool::load(int fd, int64_t offset, int64_t length, int priority __unused)
-{
-    ALOGV("load: fd=%d, offset=%" PRId64 ", length=%" PRId64 ", priority=%d",
-            fd, offset, length, priority);
-    int sampleID;
-    {
-        Mutex::Autolock lock(&mLock);
-        sampleID = ++mNextSampleID;
-        sp<Sample> sample = new Sample(sampleID, fd, offset, length);
-        mSamples.add(sampleID, sample);
-        sample->startLoad();
-    }
-    // mDecodeThread->loadSample() must be called outside of mLock.
-    // mDecodeThread->loadSample() may block on mDecodeThread message queue space;
-    // the message queue emptying may block on SoundPool::findSample().
-    //
-    // It theoretically possible that sample loads might decode out-of-order.
-    mDecodeThread->loadSample(sampleID);
-    return sampleID;
-}
-
-bool SoundPool::unload(int sampleID)
-{
-    ALOGV("unload: sampleID=%d", sampleID);
-    Mutex::Autolock lock(&mLock);
-    return mSamples.removeItem(sampleID) >= 0; // removeItem() returns index or BAD_VALUE
-}
-
-int SoundPool::play(int sampleID, float leftVolume, float rightVolume,
-        int priority, int loop, float rate)
-{
-    ALOGV("play sampleID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f",
-            sampleID, leftVolume, rightVolume, priority, loop, rate);
-    SoundChannel* channel;
-    int channelID;
-
-    Mutex::Autolock lock(&mLock);
-
-    if (mQuit) {
-        return 0;
-    }
-    // is sample ready?
-    sp<Sample> sample(findSample_l(sampleID));
-    if ((sample == 0) || (sample->state() != Sample::READY)) {
-        ALOGW("  sample %d not READY", sampleID);
+    auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
+    const std::shared_ptr<soundpool::Sound> sound = mSoundManager.findSound(soundID);
+    if (sound == nullptr || sound->getState() != soundpool::Sound::READY) {
+        ALOGW("%s soundID %d not READY", __func__, soundID);
         return 0;
     }
 
-    dump();
-
-    // allocate a channel
-    channel = allocateChannel_l(priority, sampleID);
-
-    // no channel allocated - return 0
-    if (!channel) {
-        ALOGV("No channel allocated");
-        return 0;
-    }
-
-    channelID = ++mNextChannelID;
-
-    ALOGV("play channel %p state = %d", channel, channel->state());
-    channel->play(sample, channelID, leftVolume, rightVolume, priority, loop, rate);
-    return channelID;
-}
-
-SoundChannel* SoundPool::allocateChannel_l(int priority, int sampleID)
-{
-    List<SoundChannel*>::iterator iter;
-    SoundChannel* channel = NULL;
-
-    // check if channel for given sampleID still available
-    if (!mChannels.empty()) {
-        for (iter = mChannels.begin(); iter != mChannels.end(); ++iter) {
-            if (sampleID == (*iter)->getPrevSampleID() && (*iter)->state() == SoundChannel::IDLE) {
-                channel = *iter;
-                mChannels.erase(iter);
-                ALOGV("Allocated recycled channel for same sampleID");
-                break;
-            }
-        }
-    }
-
-    // allocate any channel
-    if (!channel && !mChannels.empty()) {
-        iter = mChannels.begin();
-        if (priority >= (*iter)->priority()) {
-            channel = *iter;
-            mChannels.erase(iter);
-            ALOGV("Allocated active channel");
-        }
-    }
-
-    // update priority and put it back in the list
-    if (channel) {
-        channel->setPriority(priority);
-        for (iter = mChannels.begin(); iter != mChannels.end(); ++iter) {
-            if (priority < (*iter)->priority()) {
-                break;
-            }
-        }
-        mChannels.insert(iter, channel);
-    }
-    return channel;
-}
-
-// move a channel from its current position to the front of the list
-void SoundPool::moveToFront_l(SoundChannel* channel)
-{
-    for (List<SoundChannel*>::iterator iter = mChannels.begin(); iter != mChannels.end(); ++iter) {
-        if (*iter == channel) {
-            mChannels.erase(iter);
-            mChannels.push_front(channel);
-            break;
-        }
-    }
-}
-
-void SoundPool::pause(int channelID)
-{
-    ALOGV("pause(%d)", channelID);
-    Mutex::Autolock lock(&mLock);
-    SoundChannel* channel = findChannel(channelID);
-    if (channel) {
-        channel->pause();
-    }
+    const int32_t streamID = mStreamManager.queueForPlay(
+            sound, soundID, leftVolume, rightVolume, priority, loop, rate);
+    ALOGV("%s returned %d", __func__, streamID);
+    return streamID;
 }
 
 void SoundPool::autoPause()
 {
-    ALOGV("autoPause()");
-    Mutex::Autolock lock(&mLock);
-    for (int i = 0; i < mMaxChannels; ++i) {
-        SoundChannel* channel = &mChannelPool[i];
-        channel->autoPause();
-    }
-}
-
-void SoundPool::resume(int channelID)
-{
-    ALOGV("resume(%d)", channelID);
-    Mutex::Autolock lock(&mLock);
-    SoundChannel* channel = findChannel(channelID);
-    if (channel) {
-        channel->resume();
-    }
-}
-
-void SoundPool::mute(bool muting)
-{
-    ALOGV("mute(%d)", muting);
-    Mutex::Autolock lock(&mLock);
-    mMuted = muting;
-    if (!mChannels.empty()) {
-            for (List<SoundChannel*>::iterator iter = mChannels.begin();
-                    iter != mChannels.end(); ++iter) {
-                (*iter)->mute(muting);
-            }
-        }
+    ALOGV("%s()", __func__);
+    auto apiLock = std::make_unique<std::lock_guard<std::mutex>>(mApiLock);
+    mStreamManager.forEach([](soundpool::Stream *stream) { stream->autoPause(); });
 }
 
 void SoundPool::autoResume()
 {
-    ALOGV("autoResume()");
-    Mutex::Autolock lock(&mLock);
-    for (int i = 0; i < mMaxChannels; ++i) {
-        SoundChannel* channel = &mChannelPool[i];
-        channel->autoResume();
+    ALOGV("%s()", __func__);
+    auto apiLock = std::make_unique<std::lock_guard<std::mutex>>(mApiLock);
+    mStreamManager.forEach([](soundpool::Stream *stream) { stream->autoResume(); });
+}
+
+void SoundPool::mute(bool muting)
+{
+    ALOGV("%s(%d)", __func__, muting);
+    auto apiLock = std::make_unique<std::lock_guard<std::mutex>>(mApiLock);
+    mStreamManager.forEach([=](soundpool::Stream *stream) { stream->mute(muting); });
+}
+
+void SoundPool::pause(int32_t streamID)
+{
+    ALOGV("%s(%d)", __func__, streamID);
+    auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
+    if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
+        stream->pause(streamID);
     }
 }
 
-void SoundPool::stop(int channelID)
+void SoundPool::resume(int32_t streamID)
 {
-    ALOGV("stop(%d)", channelID);
-    Mutex::Autolock lock(&mLock);
-    SoundChannel* channel = findChannel(channelID);
-    if (channel) {
-        channel->stop();
-    } else {
-        channel = findNextChannel(channelID);
-        if (channel)
-            channel->clearNextEvent();
+    ALOGV("%s(%d)", __func__, streamID);
+    auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
+    if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
+        stream->resume(streamID);
     }
 }
 
-void SoundPool::setVolume(int channelID, float leftVolume, float rightVolume)
+void SoundPool::stop(int32_t streamID)
 {
-    Mutex::Autolock lock(&mLock);
-    SoundChannel* channel = findChannel(channelID);
-    if (channel) {
-        channel->setVolume(leftVolume, rightVolume);
+    ALOGV("%s(%d)", __func__, streamID);
+    auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
+    soundpool::Stream* stream = mStreamManager.findStream(streamID);
+    if (stream != nullptr && stream->requestStop(streamID)) {
+        mStreamManager.moveToRestartQueue(stream);
     }
 }
 
-void SoundPool::setPriority(int channelID, int priority)
+void SoundPool::setVolume(int32_t streamID, float leftVolume, float rightVolume)
 {
-    ALOGV("setPriority(%d, %d)", channelID, priority);
-    Mutex::Autolock lock(&mLock);
-    SoundChannel* channel = findChannel(channelID);
-    if (channel) {
-        channel->setPriority(priority);
+    ALOGV("%s(%d, %f %f)", __func__, streamID, leftVolume, rightVolume);
+    if (checkVolume(&leftVolume, &rightVolume)) return;
+    auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
+    if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
+        stream->setVolume(streamID, leftVolume, rightVolume);
     }
 }
 
-void SoundPool::setLoop(int channelID, int loop)
+void SoundPool::setPriority(int32_t streamID, int32_t priority)
 {
-    ALOGV("setLoop(%d, %d)", channelID, loop);
-    Mutex::Autolock lock(&mLock);
-    SoundChannel* channel = findChannel(channelID);
-    if (channel) {
-        channel->setLoop(loop);
+    ALOGV("%s(%d, %d)", __func__, streamID, priority);
+    if (checkPriority(&priority)) return;
+    auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
+    if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
+        stream->setPriority(streamID, priority);
     }
 }
 
-void SoundPool::setRate(int channelID, float rate)
+void SoundPool::setLoop(int32_t streamID, int32_t loop)
 {
-    ALOGV("setRate(%d, %f)", channelID, rate);
-    Mutex::Autolock lock(&mLock);
-    SoundChannel* channel = findChannel(channelID);
-    if (channel) {
-        channel->setRate(rate);
+    ALOGV("%s(%d, %d)", __func__, streamID, loop);
+    if (checkLoop(&loop)) return;
+    auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
+    if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
+        stream->setLoop(streamID, loop);
     }
 }
 
-// call with lock held
-void SoundPool::done_l(SoundChannel* channel)
+void SoundPool::setRate(int32_t streamID, float rate)
 {
-    ALOGV("done_l(%d)", channel->channelID());
-    // if "stolen", play next event
-    if (channel->nextChannelID() != 0) {
-        ALOGV("add to restart list");
-        addToRestartList(channel);
-    }
-
-    // return to idle state
-    else {
-        ALOGV("move to front");
-        moveToFront_l(channel);
+    ALOGV("%s(%d, %f)", __func__, streamID, rate);
+    if (checkRate(&rate)) return;
+    auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
+    if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
+        stream->setRate(streamID, rate);
     }
 }
 
 void SoundPool::setCallback(SoundPoolCallback* callback, void* user)
 {
-    Mutex::Autolock lock(&mCallbackLock);
-    mCallback = callback;
-    mUserData = user;
+    ALOGV("%s(%p, %p)", __func__, callback, user);
+    auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
+    mSoundManager.setCallback(this, callback, user);
 }
 
-void SoundPool::notify(SoundPoolEvent event)
+void* SoundPool::getUserData() const
 {
-    Mutex::Autolock lock(&mCallbackLock);
-    if (mCallback != NULL) {
-        mCallback(event, this, mUserData);
-    }
-}
-
-void SoundPool::dump()
-{
-    for (int i = 0; i < mMaxChannels; ++i) {
-        mChannelPool[i].dump();
-    }
-}
-
-
-Sample::Sample(int sampleID, int fd, int64_t offset, int64_t length)
-{
-    init();
-    mSampleID = sampleID;
-    mFd = dup(fd);
-    mOffset = offset;
-    mLength = length;
-    ALOGV("create sampleID=%d, fd=%d, offset=%" PRId64 " length=%" PRId64,
-        mSampleID, mFd, mLength, mOffset);
-}
-
-void Sample::init()
-{
-    mSize = 0;
-    mRefCount = 0;
-    mSampleID = 0;
-    mState = UNLOADED;
-    mFd = -1;
-    mOffset = 0;
-    mLength = 0;
-}
-
-Sample::~Sample()
-{
-    ALOGV("Sample::destructor sampleID=%d, fd=%d", mSampleID, mFd);
-    if (mFd > 0) {
-        ALOGV("close(%d)", mFd);
-        ::close(mFd);
-    }
-}
-
-static status_t decode(int fd, int64_t offset, int64_t length,
-        uint32_t *rate, int *numChannels, audio_format_t *audioFormat,
-        audio_channel_mask_t *channelMask, sp<MemoryHeapBase> heap,
-        size_t *memsize) {
-
-    ALOGV("fd %d, offset %" PRId64 ", size %" PRId64, fd, offset, length);
-    AMediaExtractor *ex = AMediaExtractor_new();
-    status_t err = AMediaExtractor_setDataSourceFd(ex, fd, offset, length);
-
-    if (err != AMEDIA_OK) {
-        AMediaExtractor_delete(ex);
-        return err;
-    }
-
-    *audioFormat = AUDIO_FORMAT_PCM_16_BIT;
-
-    size_t numTracks = AMediaExtractor_getTrackCount(ex);
-    for (size_t i = 0; i < numTracks; i++) {
-        AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
-        const char *mime;
-        if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
-            AMediaExtractor_delete(ex);
-            AMediaFormat_delete(format);
-            return UNKNOWN_ERROR;
-        }
-        if (strncmp(mime, "audio/", 6) == 0) {
-
-            AMediaCodec *codec = AMediaCodec_createDecoderByType(mime);
-            if (codec == NULL
-                    || AMediaCodec_configure(codec, format,
-                            NULL /* window */, NULL /* drm */, 0 /* flags */) != AMEDIA_OK
-                    || AMediaCodec_start(codec) != AMEDIA_OK
-                    || AMediaExtractor_selectTrack(ex, i) != AMEDIA_OK) {
-                AMediaExtractor_delete(ex);
-                AMediaCodec_delete(codec);
-                AMediaFormat_delete(format);
-                return UNKNOWN_ERROR;
-            }
-
-            bool sawInputEOS = false;
-            bool sawOutputEOS = false;
-            uint8_t* writePos = static_cast<uint8_t*>(heap->getBase());
-            size_t available = heap->getSize();
-            size_t written = 0;
-
-            AMediaFormat_delete(format);
-            format = AMediaCodec_getOutputFormat(codec);
-
-            while (!sawOutputEOS) {
-                if (!sawInputEOS) {
-                    ssize_t bufidx = AMediaCodec_dequeueInputBuffer(codec, 5000);
-                    ALOGV("input buffer %zd", bufidx);
-                    if (bufidx >= 0) {
-                        size_t bufsize;
-                        uint8_t *buf = AMediaCodec_getInputBuffer(codec, bufidx, &bufsize);
-                        if (buf == nullptr) {
-                            ALOGE("AMediaCodec_getInputBuffer returned nullptr, short decode");
-                            break;
-                        }
-                        int sampleSize = AMediaExtractor_readSampleData(ex, buf, bufsize);
-                        ALOGV("read %d", sampleSize);
-                        if (sampleSize < 0) {
-                            sampleSize = 0;
-                            sawInputEOS = true;
-                            ALOGV("EOS");
-                        }
-                        int64_t presentationTimeUs = AMediaExtractor_getSampleTime(ex);
-
-                        media_status_t mstatus = AMediaCodec_queueInputBuffer(codec, bufidx,
-                                0 /* offset */, sampleSize, presentationTimeUs,
-                                sawInputEOS ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
-                        if (mstatus != AMEDIA_OK) {
-                            // AMEDIA_ERROR_UNKNOWN == { -ERANGE -EINVAL -EACCES }
-                            ALOGE("AMediaCodec_queueInputBuffer returned status %d, short decode",
-                                    (int)mstatus);
-                            break;
-                        }
-                        (void)AMediaExtractor_advance(ex);
-                    }
-                }
-
-                AMediaCodecBufferInfo info;
-                int status = AMediaCodec_dequeueOutputBuffer(codec, &info, 1);
-                ALOGV("dequeueoutput returned: %d", status);
-                if (status >= 0) {
-                    if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
-                        ALOGV("output EOS");
-                        sawOutputEOS = true;
-                    }
-                    ALOGV("got decoded buffer size %d", info.size);
-
-                    uint8_t *buf = AMediaCodec_getOutputBuffer(codec, status, NULL /* out_size */);
-                    if (buf == nullptr) {
-                        ALOGE("AMediaCodec_getOutputBuffer returned nullptr, short decode");
-                        break;
-                    }
-                    size_t dataSize = info.size;
-                    if (dataSize > available) {
-                        dataSize = available;
-                    }
-                    memcpy(writePos, buf + info.offset, dataSize);
-                    writePos += dataSize;
-                    written += dataSize;
-                    available -= dataSize;
-                    media_status_t mstatus = AMediaCodec_releaseOutputBuffer(
-                            codec, status, false /* render */);
-                    if (mstatus != AMEDIA_OK) {
-                        // AMEDIA_ERROR_UNKNOWN == { -ERANGE -EINVAL -EACCES }
-                        ALOGE("AMediaCodec_releaseOutputBuffer returned status %d, short decode",
-                                (int)mstatus);
-                        break;
-                    }
-                    if (available == 0) {
-                        // there might be more data, but there's no space for it
-                        sawOutputEOS = true;
-                    }
-                } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
-                    ALOGV("output buffers changed");
-                } else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
-                    AMediaFormat_delete(format);
-                    format = AMediaCodec_getOutputFormat(codec);
-                    ALOGV("format changed to: %s", AMediaFormat_toString(format));
-                } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
-                    ALOGV("no output buffer right now");
-                } else if (status <= AMEDIA_ERROR_BASE) {
-                    ALOGE("decode error: %d", status);
-                    break;
-                } else {
-                    ALOGV("unexpected info code: %d", status);
-                }
-            }
-
-            (void)AMediaCodec_stop(codec);
-            (void)AMediaCodec_delete(codec);
-            (void)AMediaExtractor_delete(ex);
-            if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, (int32_t*) rate) ||
-                    !AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, numChannels)) {
-                (void)AMediaFormat_delete(format);
-                return UNKNOWN_ERROR;
-            }
-            if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_MASK,
-                    (int32_t*) channelMask)) {
-                *channelMask = AUDIO_CHANNEL_NONE;
-            }
-            (void)AMediaFormat_delete(format);
-            *memsize = written;
-            return OK;
-        }
-        (void)AMediaFormat_delete(format);
-    }
-    (void)AMediaExtractor_delete(ex);
-    return UNKNOWN_ERROR;
-}
-
-status_t Sample::doLoad()
-{
-    uint32_t sampleRate;
-    int numChannels;
-    audio_format_t format;
-    audio_channel_mask_t channelMask;
-    status_t status;
-    mHeap = new MemoryHeapBase(kDefaultHeapSize);
-
-    ALOGV("Start decode");
-    status = decode(mFd, mOffset, mLength, &sampleRate, &numChannels, &format,
-                    &channelMask, mHeap, &mSize);
-    ALOGV("close(%d)", mFd);
-    ::close(mFd);
-    mFd = -1;
-    if (status != NO_ERROR) {
-        ALOGE("Unable to load sample");
-        goto error;
-    }
-    ALOGV("pointer = %p, size = %zu, sampleRate = %u, numChannels = %d",
-          mHeap->getBase(), mSize, sampleRate, numChannels);
-
-    if (sampleRate > kMaxSampleRate) {
-       ALOGE("Sample rate (%u) out of range", sampleRate);
-       status = BAD_VALUE;
-       goto error;
-    }
-
-    if ((numChannels < 1) || (numChannels > FCC_8)) {
-        ALOGE("Sample channel count (%d) out of range", numChannels);
-        status = BAD_VALUE;
-        goto error;
-    }
-
-    mData = new MemoryBase(mHeap, 0, mSize);
-    mSampleRate = sampleRate;
-    mNumChannels = numChannels;
-    mFormat = format;
-    mChannelMask = channelMask;
-    mState = READY;
-    return NO_ERROR;
-
-error:
-    mHeap.clear();
-    return status;
-}
-
-
-void SoundChannel::init(SoundPool* soundPool)
-{
-    mSoundPool = soundPool;
-    mPrevSampleID = -1;
-}
-
-// call with sound pool lock held
-void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftVolume,
-        float rightVolume, int priority, int loop, float rate)
-{
-    sp<AudioTrack> oldTrack;
-    sp<AudioTrack> newTrack;
-    status_t status = NO_ERROR;
-
-    { // scope for the lock
-        Mutex::Autolock lock(&mLock);
-
-        ALOGV("SoundChannel::play %p: sampleID=%d, channelID=%d, leftVolume=%f, rightVolume=%f,"
-                " priority=%d, loop=%d, rate=%f",
-                this, sample->sampleID(), nextChannelID, leftVolume, rightVolume,
-                priority, loop, rate);
-
-        // if not idle, this voice is being stolen
-        if (mState != IDLE) {
-            ALOGV("channel %d stolen - event queued for channel %d", channelID(), nextChannelID);
-            mNextEvent.set(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate);
-            stop_l();
-            return;
-        }
-
-        // initialize track
-        size_t afFrameCount;
-        uint32_t afSampleRate;
-        audio_stream_type_t streamType =
-                AudioSystem::attributesToStreamType(*mSoundPool->attributes());
-        if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
-            afFrameCount = kDefaultFrameCount;
-        }
-        if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
-            afSampleRate = kDefaultSampleRate;
-        }
-        int numChannels = sample->numChannels();
-        uint32_t sampleRate = uint32_t(float(sample->sampleRate()) * rate + 0.5);
-        size_t frameCount = 0;
-
-        if (loop) {
-            const audio_format_t format = sample->format();
-            const size_t frameSize = audio_is_linear_pcm(format)
-                    ? numChannels * audio_bytes_per_sample(format) : 1;
-            frameCount = sample->size() / frameSize;
-        }
-
-#ifndef USE_SHARED_MEM_BUFFER
-        uint32_t totalFrames = (kDefaultBufferCount * afFrameCount * sampleRate) / afSampleRate;
-        // Ensure minimum audio buffer size in case of short looped sample
-        if(frameCount < totalFrames) {
-            frameCount = totalFrames;
-        }
-#endif
-
-        // check if the existing track has the same sample id.
-        if (mAudioTrack != 0 && mPrevSampleID == sample->sampleID()) {
-            // the sample rate may fail to change if the audio track is a fast track.
-            if (mAudioTrack->setSampleRate(sampleRate) == NO_ERROR) {
-                newTrack = mAudioTrack;
-                ALOGV("reusing track %p for sample %d", mAudioTrack.get(), sample->sampleID());
-            }
-        }
-        if (newTrack == 0) {
-            // mToggle toggles each time a track is started on a given channel.
-            // The toggle is concatenated with the SoundChannel address and passed to AudioTrack
-            // as callback user data. This enables the detection of callbacks received from the old
-            // audio track while the new one is being started and avoids processing them with
-            // wrong audio audio buffer size  (mAudioBufferSize)
-            unsigned long toggle = mToggle ^ 1;
-            void *userData = (void *)((unsigned long)this | toggle);
-            audio_channel_mask_t sampleChannelMask = sample->channelMask();
-            // When sample contains a not none channel mask, use it as is.
-            // Otherwise, use channel count to calculate channel mask.
-            audio_channel_mask_t channelMask = sampleChannelMask != AUDIO_CHANNEL_NONE
-                    ? sampleChannelMask : audio_channel_out_mask_from_count(numChannels);
-
-            // do not create a new audio track if current track is compatible with sample parameters
-    #ifdef USE_SHARED_MEM_BUFFER
-            newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
-                    channelMask, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData,
-                    0 /*default notification frames*/, AUDIO_SESSION_ALLOCATE,
-                    AudioTrack::TRANSFER_DEFAULT,
-                    NULL /*offloadInfo*/, -1 /*uid*/, -1 /*pid*/, mSoundPool->attributes());
-    #else
-            uint32_t bufferFrames = (totalFrames + (kDefaultBufferCount - 1)) / kDefaultBufferCount;
-            newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
-                    channelMask, frameCount, AUDIO_OUTPUT_FLAG_FAST, callback, userData,
-                    bufferFrames, AUDIO_SESSION_ALLOCATE, AudioTrack::TRANSFER_DEFAULT,
-                    NULL /*offloadInfo*/, -1 /*uid*/, -1 /*pid*/, mSoundPool->attributes());
-    #endif
-            oldTrack = mAudioTrack;
-            status = newTrack->initCheck();
-            if (status != NO_ERROR) {
-                ALOGE("Error creating AudioTrack");
-                // newTrack goes out of scope, so reference count drops to zero
-                goto exit;
-            }
-            // From now on, AudioTrack callbacks received with previous toggle value will be ignored.
-            mToggle = toggle;
-            mAudioTrack = newTrack;
-            ALOGV("using new track %p for sample %d", newTrack.get(), sample->sampleID());
-        }
-        if (mMuted) {
-            newTrack->setVolume(0.0f, 0.0f);
-        } else {
-            newTrack->setVolume(leftVolume, rightVolume);
-        }
-        newTrack->setLoop(0, frameCount, loop);
-        mPos = 0;
-        mSample = sample;
-        mChannelID = nextChannelID;
-        mPriority = priority;
-        mLoop = loop;
-        mLeftVolume = leftVolume;
-        mRightVolume = rightVolume;
-        mNumChannels = numChannels;
-        mRate = rate;
-        clearNextEvent();
-        mState = PLAYING;
-        mAudioTrack->start();
-        mAudioBufferSize = newTrack->frameCount()*newTrack->frameSize();
-    }
-
-exit:
-    ALOGV("delete oldTrack %p", oldTrack.get());
-    if (status != NO_ERROR) {
-        mAudioTrack.clear();
-    }
-}
-
-void SoundChannel::nextEvent()
-{
-    sp<Sample> sample;
-    int nextChannelID;
-    float leftVolume;
-    float rightVolume;
-    int priority;
-    int loop;
-    float rate;
-
-    // check for valid event
-    {
-        Mutex::Autolock lock(&mLock);
-        nextChannelID = mNextEvent.channelID();
-        if (nextChannelID  == 0) {
-            ALOGV("stolen channel has no event");
-            return;
-        }
-
-        sample = mNextEvent.sample();
-        leftVolume = mNextEvent.leftVolume();
-        rightVolume = mNextEvent.rightVolume();
-        priority = mNextEvent.priority();
-        loop = mNextEvent.loop();
-        rate = mNextEvent.rate();
-    }
-
-    ALOGV("Starting stolen channel %d -> %d", channelID(), nextChannelID);
-    play(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate);
-}
-
-void SoundChannel::callback(int event, void* user, void *info)
-{
-    SoundChannel* channel = static_cast<SoundChannel*>((void *)((unsigned long)user & ~1));
-
-    channel->process(event, info, (unsigned long)user & 1);
-}
-
-void SoundChannel::process(int event, void *info, unsigned long toggle)
-{
-    //ALOGV("process(%d)", mChannelID);
-
-    Mutex::Autolock lock(&mLock);
-
-    AudioTrack::Buffer* b = NULL;
-    if (event == AudioTrack::EVENT_MORE_DATA) {
-       b = static_cast<AudioTrack::Buffer *>(info);
-    }
-
-    if (mToggle != toggle) {
-        ALOGV("process wrong toggle %p channel %d", this, mChannelID);
-        if (b != NULL) {
-            b->size = 0;
-        }
-        return;
-    }
-
-    sp<Sample> sample = mSample;
-
-//    ALOGV("SoundChannel::process event %d", event);
-
-    if (event == AudioTrack::EVENT_MORE_DATA) {
-
-        // check for stop state
-        if (b->size == 0) return;
-
-        if (mState == IDLE) {
-            b->size = 0;
-            return;
-        }
-
-        if (sample != 0) {
-            // fill buffer
-            uint8_t* q = (uint8_t*) b->i8;
-            size_t count = 0;
-
-            if (mPos < (int)sample->size()) {
-                uint8_t* p = sample->data() + mPos;
-                count = sample->size() - mPos;
-                if (count > b->size) {
-                    count = b->size;
-                }
-                memcpy(q, p, count);
-//              ALOGV("fill: q=%p, p=%p, mPos=%u, b->size=%u, count=%d", q, p, mPos, b->size,
-//                      count);
-            } else if (mPos < mAudioBufferSize) {
-                count = mAudioBufferSize - mPos;
-                if (count > b->size) {
-                    count = b->size;
-                }
-                memset(q, 0, count);
-//              ALOGV("fill extra: q=%p, mPos=%u, b->size=%u, count=%d", q, mPos, b->size, count);
-            }
-
-            mPos += count;
-            b->size = count;
-            //ALOGV("buffer=%p, [0]=%d", b->i16, b->i16[0]);
-        }
-    } else if (event == AudioTrack::EVENT_UNDERRUN || event == AudioTrack::EVENT_BUFFER_END) {
-        ALOGV("process %p channel %d event %s",
-              this, mChannelID, (event == AudioTrack::EVENT_UNDERRUN) ? "UNDERRUN" :
-                      "BUFFER_END");
-        // Only BUFFER_END should happen as we use static tracks.
-        setVolume_l(0.f, 0.f);  // set volume to 0 to indicate no need to ramp volume down.
-        mSoundPool->addToStopList(this);
-    } else if (event == AudioTrack::EVENT_LOOP_END) {
-        ALOGV("End loop %p channel %d", this, mChannelID);
-    } else if (event == AudioTrack::EVENT_NEW_IAUDIOTRACK) {
-        ALOGV("process %p channel %d NEW_IAUDIOTRACK", this, mChannelID);
-    } else {
-        ALOGW("SoundChannel::process unexpected event %d", event);
-    }
-}
-
-
-// call with lock held
-bool SoundChannel::doStop_l()
-{
-    if (mState != IDLE) {
-        ALOGV("stop");
-        if (mLeftVolume != 0.f || mRightVolume != 0.f) {
-            setVolume_l(0.f, 0.f);
-            if (mSoundPool->attributes()->usage != AUDIO_USAGE_GAME) {
-                // Since we're forcibly halting the previously playing content,
-                // we sleep here to ensure the volume is ramped down before we stop the track.
-                // Ideally the sleep time is the mixer period, or an approximation thereof
-                // (Fast vs Normal tracks are different).
-                ALOGV("sleeping: ChannelID:%d  SampleID:%d", mChannelID, mSample->sampleID());
-                std::this_thread::sleep_for(std::chrono::milliseconds(20));
-            }
-        }
-        mAudioTrack->stop();
-        mPrevSampleID = mSample->sampleID();
-        mSample.clear();
-        mState = IDLE;
-        mPriority = IDLE_PRIORITY;
-        return true;
-    }
-    return false;
-}
-
-// call with lock held and sound pool lock held
-void SoundChannel::stop_l()
-{
-    if (doStop_l()) {
-        mSoundPool->done_l(this);
-    }
-}
-
-// call with sound pool lock held
-void SoundChannel::stop()
-{
-    bool stopped;
-    {
-        Mutex::Autolock lock(&mLock);
-        stopped = doStop_l();
-    }
-
-    if (stopped) {
-        mSoundPool->done_l(this);
-    }
-}
-
-//FIXME: Pause is a little broken right now
-void SoundChannel::pause()
-{
-    Mutex::Autolock lock(&mLock);
-    if (mState == PLAYING) {
-        ALOGV("pause track");
-        mState = PAUSED;
-        mAudioTrack->pause();
-    }
-}
-
-void SoundChannel::autoPause()
-{
-    Mutex::Autolock lock(&mLock);
-    if (mState == PLAYING) {
-        ALOGV("pause track");
-        mState = PAUSED;
-        mAutoPaused = true;
-        mAudioTrack->pause();
-    }
-}
-
-void SoundChannel::resume()
-{
-    Mutex::Autolock lock(&mLock);
-    if (mState == PAUSED) {
-        ALOGV("resume track");
-        mState = PLAYING;
-        mAutoPaused = false;
-        mAudioTrack->start();
-    }
-}
-
-void SoundChannel::autoResume()
-{
-    Mutex::Autolock lock(&mLock);
-    if (mAutoPaused && (mState == PAUSED)) {
-        ALOGV("resume track");
-        mState = PLAYING;
-        mAutoPaused = false;
-        mAudioTrack->start();
-    }
-}
-
-void SoundChannel::setRate(float rate)
-{
-    Mutex::Autolock lock(&mLock);
-    if (mAudioTrack != NULL && mSample != 0) {
-        uint32_t sampleRate = uint32_t(float(mSample->sampleRate()) * rate + 0.5);
-        mAudioTrack->setSampleRate(sampleRate);
-        mRate = rate;
-    }
-}
-
-// call with lock held
-void SoundChannel::setVolume_l(float leftVolume, float rightVolume)
-{
-    mLeftVolume = leftVolume;
-    mRightVolume = rightVolume;
-    if (mAudioTrack != NULL && !mMuted)
-        mAudioTrack->setVolume(leftVolume, rightVolume);
-}
-
-void SoundChannel::setVolume(float leftVolume, float rightVolume)
-{
-    Mutex::Autolock lock(&mLock);
-    setVolume_l(leftVolume, rightVolume);
-}
-
-void SoundChannel::mute(bool muting)
-{
-    Mutex::Autolock lock(&mLock);
-    mMuted = muting;
-    if (mAudioTrack != NULL) {
-        if (mMuted) {
-            mAudioTrack->setVolume(0.0f, 0.0f);
-        } else {
-            mAudioTrack->setVolume(mLeftVolume, mRightVolume);
-        }
-    }
-}
-
-void SoundChannel::setLoop(int loop)
-{
-    Mutex::Autolock lock(&mLock);
-    if (mAudioTrack != NULL && mSample != 0) {
-        uint32_t loopEnd = mSample->size()/mNumChannels/
-            ((mSample->format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t));
-        mAudioTrack->setLoop(0, loopEnd, loop);
-        mLoop = loop;
-    }
-}
-
-SoundChannel::~SoundChannel()
-{
-    ALOGV("SoundChannel destructor %p", this);
-    {
-        Mutex::Autolock lock(&mLock);
-        clearNextEvent();
-        doStop_l();
-    }
-    // do not call AudioTrack destructor with mLock held as it will wait for the AudioTrack
-    // callback thread to exit which may need to execute process() and acquire the mLock.
-    mAudioTrack.clear();
-}
-
-void SoundChannel::dump()
-{
-    ALOGV("mState = %d mChannelID=%d, mNumChannels=%d, mPos = %d, mPriority=%d, mLoop=%d",
-            mState, mChannelID, mNumChannels, mPos, mPriority, mLoop);
-}
-
-void SoundEvent::set(const sp<Sample>& sample, int channelID, float leftVolume,
-            float rightVolume, int priority, int loop, float rate)
-{
-    mSample = sample;
-    mChannelID = channelID;
-    mLeftVolume = leftVolume;
-    mRightVolume = rightVolume;
-    mPriority = priority;
-    mLoop = loop;
-    mRate =rate;
+    ALOGV("%s()", __func__);
+    auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
+    return mSoundManager.getUserData();
 }
 
 } // end namespace android
diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h
index 01e4faa..d5b16ef 100644
--- a/media/jni/soundpool/SoundPool.h
+++ b/media/jni/soundpool/SoundPool.h
@@ -14,227 +14,59 @@
  * limitations under the License.
  */
 
-#ifndef SOUNDPOOL_H_
-#define SOUNDPOOL_H_
+#pragma once
 
-#include <utils/threads.h>
-#include <utils/List.h>
-#include <utils/Vector.h>
-#include <utils/KeyedVector.h>
-#include <media/AudioTrack.h>
-#include <binder/MemoryHeapBase.h>
-#include <binder/MemoryBase.h>
+#include "SoundManager.h"
+#include "StreamManager.h"
 
 namespace android {
 
-static const int IDLE_PRIORITY = -1;
-
-// forward declarations
-class SoundEvent;
-class SoundPoolThread;
-class SoundPool;
-
-// for queued events
-class SoundPoolEvent {
-public:
-    explicit SoundPoolEvent(int msg, int arg1=0, int arg2=0) :
-        mMsg(msg), mArg1(arg1), mArg2(arg2) {}
-    int         mMsg;
-    int         mArg1;
-    int         mArg2;
-    enum MessageType { INVALID, SAMPLE_LOADED };
-};
-
-// callback function prototype
-typedef void SoundPoolCallback(SoundPoolEvent event, SoundPool* soundPool, void* user);
-
-// tracks samples used by application
-class Sample  : public RefBase {
-public:
-    enum sample_state { UNLOADED, LOADING, READY, UNLOADING };
-    Sample(int sampleID, int fd, int64_t offset, int64_t length);
-    ~Sample();
-    int sampleID() { return mSampleID; }
-    int numChannels() { return mNumChannels; }
-    int sampleRate() { return mSampleRate; }
-    audio_format_t format() { return mFormat; }
-    audio_channel_mask_t channelMask() { return mChannelMask; }
-    size_t size() { return mSize; }
-    int state() { return mState; }
-    uint8_t* data() { return static_cast<uint8_t*>(mData->unsecurePointer()); }
-    status_t doLoad();
-    void startLoad() { mState = LOADING; }
-    sp<IMemory> getIMemory() { return mData; }
-
-private:
-    void init();
-
-    size_t               mSize;
-    volatile int32_t     mRefCount;
-    uint16_t             mSampleID;
-    uint16_t             mSampleRate;
-    uint8_t              mState;
-    uint8_t              mNumChannels;
-    audio_format_t       mFormat;
-    audio_channel_mask_t mChannelMask;
-    int                  mFd;
-    int64_t              mOffset;
-    int64_t              mLength;
-    sp<IMemory>          mData;
-    sp<MemoryHeapBase>   mHeap;
-};
-
-// stores pending events for stolen channels
-class SoundEvent
-{
-public:
-    SoundEvent() : mChannelID(0), mLeftVolume(0), mRightVolume(0),
-            mPriority(IDLE_PRIORITY), mLoop(0), mRate(0) {}
-    void set(const sp<Sample>& sample, int channelID, float leftVolume,
-            float rightVolume, int priority, int loop, float rate);
-    sp<Sample>      sample() { return mSample; }
-    int             channelID() { return mChannelID; }
-    float           leftVolume() { return mLeftVolume; }
-    float           rightVolume() { return mRightVolume; }
-    int             priority() { return mPriority; }
-    int             loop() { return mLoop; }
-    float           rate() { return mRate; }
-    void            clear() { mChannelID = 0; mSample.clear(); }
-
-protected:
-    sp<Sample>      mSample;
-    int             mChannelID;
-    float           mLeftVolume;
-    float           mRightVolume;
-    int             mPriority;
-    int             mLoop;
-    float           mRate;
-};
-
-// for channels aka AudioTracks
-class SoundChannel : public SoundEvent {
-public:
-    enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING };
-    SoundChannel() : mState(IDLE), mNumChannels(1),
-            mPos(0), mToggle(0), mAutoPaused(false), mMuted(false) {}
-    ~SoundChannel();
-    void init(SoundPool* soundPool);
-    void play(const sp<Sample>& sample, int channelID, float leftVolume, float rightVolume,
-            int priority, int loop, float rate);
-    void setVolume_l(float leftVolume, float rightVolume);
-    void setVolume(float leftVolume, float rightVolume);
-    void mute(bool muting);
-    void stop_l();
-    void stop();
-    void pause();
-    void autoPause();
-    void resume();
-    void autoResume();
-    void setRate(float rate);
-    int state() { return mState; }
-    void setPriority(int priority) { mPriority = priority; }
-    void setLoop(int loop);
-    int numChannels() { return mNumChannels; }
-    void clearNextEvent() { mNextEvent.clear(); }
-    void nextEvent();
-    int nextChannelID() { return mNextEvent.channelID(); }
-    void dump();
-    int getPrevSampleID(void) { return mPrevSampleID; }
-
-private:
-    static void callback(int event, void* user, void *info);
-    void process(int event, void *info, unsigned long toggle);
-    bool doStop_l();
-
-    SoundPool*          mSoundPool;
-    sp<AudioTrack>      mAudioTrack;
-    SoundEvent          mNextEvent;
-    Mutex               mLock;
-    int                 mState;
-    int                 mNumChannels;
-    int                 mPos;
-    int                 mAudioBufferSize;
-    unsigned long       mToggle;
-    bool                mAutoPaused;
-    int                 mPrevSampleID;
-    bool                mMuted;
-};
-
-// application object for managing a pool of sounds
+/**
+ * Native class for Java SoundPool, manages a pool of sounds.
+ *
+ * See the Android SoundPool Java documentation for description of valid values.
+ * https://developer.android.com/reference/android/media/SoundPool
+ */
 class SoundPool {
-    friend class SoundPoolThread;
-    friend class SoundChannel;
 public:
-    SoundPool(int maxChannels, const audio_attributes_t* pAttributes);
+    SoundPool(int32_t maxStreams, const audio_attributes_t* attributes);
     ~SoundPool();
-    int load(int fd, int64_t offset, int64_t length, int priority);
-    bool unload(int sampleID);
-    int play(int sampleID, float leftVolume, float rightVolume, int priority,
-            int loop, float rate);
-    void pause(int channelID);
-    void mute(bool muting);
+
+    // SoundPool Java API support
+    int32_t load(int fd, int64_t offset, int64_t length, int32_t priority);
+    bool unload(int32_t soundID);
+    int32_t play(int32_t soundID, float leftVolume, float rightVolume, int32_t priority,
+            int32_t loop, float rate);
+    void pause(int32_t streamID);
     void autoPause();
-    void resume(int channelID);
+    void resume(int32_t streamID);
     void autoResume();
-    void stop(int channelID);
-    void setVolume(int channelID, float leftVolume, float rightVolume);
-    void setPriority(int channelID, int priority);
-    void setLoop(int channelID, int loop);
-    void setRate(int channelID, float rate);
-    const audio_attributes_t* attributes() { return &mAttributes; }
-
-    // called from SoundPoolThread
-    void sampleLoaded(int sampleID);
-    sp<Sample> findSample(int sampleID);
-
-    // called from AudioTrack thread
-    void done_l(SoundChannel* channel);
-
-    // callback function
+    void stop(int32_t streamID);
+    void setVolume(int32_t streamID, float leftVolume, float rightVolume);
+    void setPriority(int32_t streamID, int32_t priority);
+    void setLoop(int32_t streamID, int32_t loop);
+    void setRate(int32_t streamID, float rate);
     void setCallback(SoundPoolCallback* callback, void* user);
-    void* getUserData() { return mUserData; }
+    void* getUserData() const;
+
+    // not exposed in the public Java API, used for internal playerSetVolume() muting.
+    void mute(bool muting);
 
 private:
-    SoundPool() {} // no default constructor
-    bool startThreads();
-    sp<Sample> findSample_l(int sampleID);
-    SoundChannel* findChannel (int channelID);
-    SoundChannel* findNextChannel (int channelID);
-    SoundChannel* allocateChannel_l(int priority, int sampleID);
-    void moveToFront_l(SoundChannel* channel);
-    void notify(SoundPoolEvent event);
-    void dump();
 
-    // restart thread
-    void addToRestartList(SoundChannel* channel);
-    void addToStopList(SoundChannel* channel);
-    static int beginThread(void* arg);
-    int run();
-    void quit();
+    // Constructor initialized variables
+    // Can access without lock as they are internally locked,
+    // though care needs to be taken that the final result composed of
+    // individually consistent actions are consistent.
+    soundpool::SoundManager  mSoundManager;
+    soundpool::StreamManager mStreamManager;
 
-    Mutex                   mLock;
-    Mutex                   mRestartLock;
-    Condition               mCondition;
-    SoundPoolThread*        mDecodeThread;
-    SoundChannel*           mChannelPool;
-    List<SoundChannel*>     mChannels;
-    List<SoundChannel*>     mRestart;
-    List<SoundChannel*>     mStop;
-    DefaultKeyedVector< int, sp<Sample> >   mSamples;
-    int                     mMaxChannels;
-    audio_attributes_t      mAttributes;
-    int                     mAllocated;
-    int                     mNextSampleID;
-    int                     mNextChannelID;
-    bool                    mQuit;
-    bool                    mMuted;
-
-    // callback
-    Mutex                   mCallbackLock;
-    SoundPoolCallback*      mCallback;
-    void*                   mUserData;
+    // mApiLock serializes SoundPool application calls (configurable by kUseApiLock).
+    // It only locks at the SoundPool layer and not below.  At this level,
+    // mApiLock is only required for autoPause() and autoResume() to prevent zippering
+    // of the individual pauses and resumes, and mute() for self-interaction with itself.
+    // It is optional for all other apis.
+    mutable std::mutex        mApiLock;
 };
 
 } // end namespace android
-
-#endif /*SOUNDPOOL_H_*/
diff --git a/media/jni/soundpool/SoundPoolThread.cpp b/media/jni/soundpool/SoundPoolThread.cpp
deleted file mode 100644
index ba3b482..0000000
--- a/media/jni/soundpool/SoundPoolThread.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2007 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 "SoundPoolThread"
-#include "utils/Log.h"
-
-#include "SoundPoolThread.h"
-
-namespace android {
-
-void SoundPoolThread::write(SoundPoolMsg msg) {
-    Mutex::Autolock lock(&mLock);
-    while (mMsgQueue.size() >= maxMessages) {
-        mCondition.wait(mLock);
-    }
-
-    // if thread is quitting, don't add to queue
-    if (mRunning) {
-        mMsgQueue.push(msg);
-        mCondition.signal();
-    }
-}
-
-const SoundPoolMsg SoundPoolThread::read() {
-    Mutex::Autolock lock(&mLock);
-    while (mMsgQueue.size() == 0) {
-        mCondition.wait(mLock);
-    }
-    SoundPoolMsg msg = mMsgQueue[0];
-    mMsgQueue.removeAt(0);
-    mCondition.signal();
-    return msg;
-}
-
-void SoundPoolThread::quit() {
-    Mutex::Autolock lock(&mLock);
-    if (mRunning) {
-        mRunning = false;
-        mMsgQueue.clear();
-        mMsgQueue.push(SoundPoolMsg(SoundPoolMsg::KILL, 0));
-        mCondition.signal();
-        mCondition.wait(mLock);
-    }
-    ALOGV("return from quit");
-}
-
-SoundPoolThread::SoundPoolThread(SoundPool* soundPool) :
-    mSoundPool(soundPool)
-{
-    mMsgQueue.setCapacity(maxMessages);
-    if (createThreadEtc(beginThread, this, "SoundPoolThread")) {
-        mRunning = true;
-    }
-}
-
-SoundPoolThread::~SoundPoolThread()
-{
-    quit();
-}
-
-int SoundPoolThread::beginThread(void* arg) {
-    ALOGV("beginThread");
-    SoundPoolThread* soundPoolThread = (SoundPoolThread*)arg;
-    return soundPoolThread->run();
-}
-
-int SoundPoolThread::run() {
-    ALOGV("run");
-    for (;;) {
-        SoundPoolMsg msg = read();
-        ALOGV("Got message m=%d, mData=%d", msg.mMessageType, msg.mData);
-        switch (msg.mMessageType) {
-        case SoundPoolMsg::KILL:
-            ALOGV("goodbye");
-            return NO_ERROR;
-        case SoundPoolMsg::LOAD_SAMPLE:
-            doLoadSample(msg.mData);
-            break;
-        default:
-            ALOGW("run: Unrecognized message %d\n",
-                    msg.mMessageType);
-            break;
-        }
-    }
-}
-
-void SoundPoolThread::loadSample(int sampleID) {
-    write(SoundPoolMsg(SoundPoolMsg::LOAD_SAMPLE, sampleID));
-}
-
-void SoundPoolThread::doLoadSample(int sampleID) {
-    sp <Sample> sample = mSoundPool->findSample(sampleID);
-    status_t status = -1;
-    if (sample != 0) {
-        status = sample->doLoad();
-    }
-    mSoundPool->notify(SoundPoolEvent(SoundPoolEvent::SAMPLE_LOADED, sampleID, status));
-}
-
-} // end namespace android
diff --git a/media/jni/soundpool/SoundPoolThread.h b/media/jni/soundpool/SoundPoolThread.h
deleted file mode 100644
index 7b3e1dd..0000000
--- a/media/jni/soundpool/SoundPoolThread.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#ifndef SOUNDPOOLTHREAD_H_
-#define SOUNDPOOLTHREAD_H_
-
-#include <utils/threads.h>
-#include <utils/Vector.h>
-#include <media/AudioTrack.h>
-
-#include "SoundPool.h"
-
-namespace android {
-
-class SoundPoolMsg {
-public:
-    enum MessageType { INVALID, KILL, LOAD_SAMPLE };
-    SoundPoolMsg() : mMessageType(INVALID), mData(0) {}
-    SoundPoolMsg(MessageType MessageType, int data) :
-        mMessageType(MessageType), mData(data) {}
-    uint16_t         mMessageType;
-    uint16_t         mData;
-};
-
-/*
- * This class handles background requests from the SoundPool
- */
-class SoundPoolThread {
-public:
-    explicit SoundPoolThread(SoundPool* SoundPool);
-    ~SoundPoolThread();
-    void loadSample(int sampleID);
-    void quit();
-    void write(SoundPoolMsg msg);
-
-private:
-    static const size_t maxMessages = 128;
-
-    static int beginThread(void* arg);
-    int run();
-    void doLoadSample(int sampleID);
-    const SoundPoolMsg read();
-
-    Mutex                   mLock;
-    Condition               mCondition;
-    Vector<SoundPoolMsg>    mMsgQueue;
-    SoundPool*              mSoundPool;
-    bool                    mRunning;
-};
-
-} // end namespace android
-
-#endif /*SOUNDPOOLTHREAD_H_*/
diff --git a/media/jni/soundpool/Stream.cpp b/media/jni/soundpool/Stream.cpp
new file mode 100644
index 0000000..e7d4d90
--- /dev/null
+++ b/media/jni/soundpool/Stream.cpp
@@ -0,0 +1,448 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoundPool::Stream"
+#include <utils/Log.h>
+
+#include "Stream.h"
+
+#include "StreamManager.h"
+
+namespace android::soundpool {
+
+Stream::~Stream()
+{
+    ALOGV("%s(%p)", __func__, this);
+}
+
+void Stream::autoPause()
+{
+    std::lock_guard lock(mLock);
+    if (mState == PLAYING) {
+        ALOGV("%s: track streamID: %d", __func__, (int)mStreamID);
+        mState = PAUSED;
+        mAutoPaused = true;
+        if (mAudioTrack != nullptr) {
+            mAudioTrack->pause();
+        }
+    }
+}
+
+void Stream::autoResume()
+{
+    std::lock_guard lock(mLock);
+    if (mAutoPaused) {
+        if (mState == PAUSED) {
+            ALOGV("%s: track streamID: %d", __func__, (int)mStreamID);
+            mState = PLAYING;
+            if (mAudioTrack != nullptr) {
+                mAudioTrack->start();
+            }
+        }
+        mAutoPaused = false; // New for R: always reset autopause (consistent with API spec).
+    }
+}
+
+void Stream::mute(bool muting)
+{
+    std::lock_guard lock(mLock);
+    mMuted = muting;
+    if (mAudioTrack != nullptr) {
+        if (mMuted) {
+            mAudioTrack->setVolume(0.0f, 0.0f);
+        } else {
+            mAudioTrack->setVolume(mLeftVolume, mRightVolume);
+        }
+    }
+}
+
+void Stream::pause(int32_t streamID)
+{
+    std::lock_guard lock(mLock);
+    if (streamID == mStreamID) {
+        if (mState == PLAYING) {
+            ALOGV("%s: track streamID: %d", __func__, streamID);
+            mState = PAUSED;
+            if (mAudioTrack != nullptr) {
+                mAudioTrack->pause();
+            }
+        }
+    }
+}
+
+void Stream::resume(int32_t streamID)
+{
+    std::lock_guard lock(mLock);
+    if (streamID == mStreamID) {
+         if (mState == PAUSED) {
+            ALOGV("%s: track streamID: %d", __func__, streamID);
+            mState = PLAYING;
+            if (mAudioTrack != nullptr) {
+                mAudioTrack->start();
+            }
+            mAutoPaused = false; // TODO: is this right? (ambiguous per spec), move outside?
+        }
+    }
+}
+
+void Stream::setRate(int32_t streamID, float rate)
+{
+    std::lock_guard lock(mLock);
+    if (streamID == mStreamID) {
+        mRate = rate;
+        if (mAudioTrack != nullptr && mSound != nullptr) {
+            const uint32_t sampleRate = uint32_t(float(mSound->getSampleRate()) * rate + 0.5);
+            mAudioTrack->setSampleRate(sampleRate);
+        }
+    }
+}
+
+void Stream::setVolume_l(float leftVolume, float rightVolume)
+{
+    mLeftVolume = leftVolume;
+    mRightVolume = rightVolume;
+    if (mAudioTrack != nullptr && !mMuted) {
+        mAudioTrack->setVolume(leftVolume, rightVolume);
+    }
+}
+
+void Stream::setVolume(int32_t streamID, float leftVolume, float rightVolume)
+{
+    std::lock_guard lock(mLock);
+    if (streamID == mStreamID) {
+        setVolume_l(leftVolume, rightVolume);
+    }
+}
+
+void Stream::setPriority(int32_t streamID, int32_t priority)
+{
+    std::lock_guard lock(mLock);
+    if (streamID == mStreamID) {
+        mPriority = priority;
+    }
+}
+
+void Stream::setLoop(int32_t streamID, int32_t loop)
+{
+    std::lock_guard lock(mLock);
+    if (streamID == mStreamID) {
+        if (mAudioTrack != nullptr && mSound != nullptr) {
+            const uint32_t loopEnd = mSound->getSizeInBytes() / mSound->getChannelCount() /
+                (mSound->getFormat() == AUDIO_FORMAT_PCM_16_BIT
+                        ? sizeof(int16_t) : sizeof(uint8_t));
+            mAudioTrack->setLoop(0, loopEnd, loop);
+        }
+        mLoop = loop;
+    }
+}
+
+void Stream::setPlay(
+        int32_t streamID, const std::shared_ptr<Sound> &sound, int32_t soundID,
+        float leftVolume, float rightVolume, int32_t priority, int32_t loop, float rate)
+{
+    std::lock_guard lock(mLock);
+    // We must be idle, or we must be repurposing a pending Stream.
+    LOG_ALWAYS_FATAL_IF(mState != IDLE && mAudioTrack != nullptr, "State %d must be IDLE", mState);
+    mSound = sound;
+    mSoundID = soundID;
+    mLeftVolume = leftVolume;
+    mRightVolume = rightVolume;
+    mPriority = priority;
+    mLoop = loop;
+    mRate = rate;
+    mState = PLAYING;
+    mAutoPaused = false;   // New for R (consistent with Java API spec).
+    mStreamID = streamID;  // prefer this to be the last, as it is an atomic sync point
+}
+
+void Stream::setStopTimeNs(int64_t stopTimeNs)
+{
+    std::lock_guard lock(mLock);
+    mStopTimeNs = stopTimeNs;
+}
+
+bool Stream::requestStop(int32_t streamID)
+{
+    std::lock_guard lock(mLock);
+    if (streamID == mStreamID) {
+        if (mAudioTrack != nullptr) {
+            if (mState == PLAYING && !mMuted && (mLeftVolume != 0.f || mRightVolume != 0.f)) {
+                setVolume_l(0.f, 0.f);
+                mStopTimeNs = systemTime() + kStopWaitTimeNs;
+            } else {
+                mStopTimeNs = systemTime();
+            }
+            return true; // must be queued on the restart list.
+        }
+        stop_l();
+    }
+    return false;
+}
+
+void Stream::stop()
+{
+    std::lock_guard lock(mLock);
+    stop_l();
+}
+
+void Stream::stop_l()
+{
+    if (mState != IDLE) {
+        if (mAudioTrack != nullptr) {
+            mAudioTrack->stop();
+        }
+        mSound.reset();
+        mState = IDLE;
+    }
+}
+
+void Stream::clearAudioTrack()
+{
+    // This will invoke the destructor which waits for the AudioTrack thread to join,
+    // and is currently the only safe way to ensure there are no callbacks afterwards.
+    mAudioTrack.clear();
+}
+
+Stream* Stream::getPairStream() const
+{
+   return mStreamManager->getPairStream(this);
+}
+
+Stream* Stream::playPairStream() {
+    Stream* pairStream = getPairStream();
+    LOG_ALWAYS_FATAL_IF(pairStream == nullptr, "No pair stream!");
+    sp<AudioTrack> releaseTracks[2];
+    {
+        // TODO: Do we really want to force a simultaneous synchronization between
+        // the stream and its pair?
+
+        // note locking order - the paired stream is obtained before the queued stream.
+        // we can invert the locking order, but it is slightly more optimal to do it this way.
+        std::lock_guard lockp(pairStream->mLock);
+        if (pairStream->mSound == nullptr) {
+            return nullptr; // no pair sound
+        }
+        {
+            std::lock_guard lock(mLock);
+            LOG_ALWAYS_FATAL_IF(mState != IDLE, "State: %d must be IDLE", mState);
+            // TODO: do we want a specific set() here?
+            pairStream->mAudioTrack = mAudioTrack;
+            pairStream->mSoundID = mSoundID; // optimization to reuse AudioTrack.
+            pairStream->mToggle = mToggle;
+            pairStream->mAutoPaused = mAutoPaused; // save autopause state
+            pairStream->mMuted = mMuted;
+            mAudioTrack.clear();  // the pair owns the audiotrack.
+            mSound.reset();
+            mSoundID = 0;
+        }
+        // TODO: do we need a specific play_l() anymore?
+        const int pairState = pairStream->mState;
+        pairStream->play_l(pairStream->mSound, pairStream->mStreamID,
+                pairStream->mLeftVolume, pairStream->mRightVolume, pairStream->mPriority,
+                pairStream->mLoop, pairStream->mRate, releaseTracks);
+        if (pairStream->mState == IDLE) {
+            return nullptr; // AudioTrack error
+        }
+        if (pairState == PAUSED) {  // reestablish pause
+            pairStream->mState = PAUSED;
+            pairStream->mAudioTrack->pause();
+        }
+    }
+    // release tracks outside of Stream lock
+    return pairStream;
+}
+
+void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID,
+        float leftVolume, float rightVolume, int32_t priority, int32_t loop, float rate,
+        sp<AudioTrack> releaseTracks[2])
+{
+    // These tracks are released without the lock.
+    sp<AudioTrack> &oldTrack = releaseTracks[0];
+    sp<AudioTrack> &newTrack = releaseTracks[1];
+    status_t status = NO_ERROR;
+
+    {
+        ALOGV("%s(%p)(soundID=%d, streamID=%d, leftVolume=%f, rightVolume=%f,"
+                " priority=%d, loop=%d, rate=%f)",
+                __func__, this, sound->getSoundID(), nextStreamID, leftVolume, rightVolume,
+                priority, loop, rate);
+
+        // initialize track
+        const audio_stream_type_t streamType =
+                AudioSystem::attributesToStreamType(*mStreamManager->getAttributes());
+        const int32_t channelCount = sound->getChannelCount();
+        const uint32_t sampleRate = uint32_t(float(sound->getSampleRate()) * rate + 0.5);
+        size_t frameCount = 0;
+
+        if (loop) {
+            const audio_format_t format = sound->getFormat();
+            const size_t frameSize = audio_is_linear_pcm(format)
+                    ? channelCount * audio_bytes_per_sample(format) : 1;
+            frameCount = sound->getSizeInBytes() / frameSize;
+        }
+
+        // check if the existing track has the same sound id.
+        if (mAudioTrack != nullptr && mSoundID == sound->getSoundID()) {
+            // the sample rate may fail to change if the audio track is a fast track.
+            if (mAudioTrack->setSampleRate(sampleRate) == NO_ERROR) {
+                newTrack = mAudioTrack;
+                ALOGV("%s: reusing track %p for sound %d",
+                        __func__, mAudioTrack.get(), sound->getSoundID());
+            }
+        }
+        if (newTrack == 0) {
+            // mToggle toggles each time a track is started on a given stream.
+            // The toggle is concatenated with the Stream address and passed to AudioTrack
+            // as callback user data. This enables the detection of callbacks received from the old
+            // audio track while the new one is being started and avoids processing them with
+            // wrong audio audio buffer size  (mAudioBufferSize)
+            auto toggle = mToggle ^ 1;
+            void* userData = (void*)((uintptr_t)this | toggle);
+            audio_channel_mask_t soundChannelMask = sound->getChannelMask();
+            // When sound contains a valid channel mask, use it as is.
+            // Otherwise, use stream count to calculate channel mask.
+            audio_channel_mask_t channelMask = soundChannelMask != AUDIO_CHANNEL_NONE
+                    ? soundChannelMask : audio_channel_out_mask_from_count(channelCount);
+
+            // do not create a new audio track if current track is compatible with sound parameters
+
+            newTrack = new AudioTrack(streamType, sampleRate, sound->getFormat(),
+                    channelMask, sound->getIMemory(), AUDIO_OUTPUT_FLAG_FAST,
+                    staticCallback, userData,
+                    0 /*default notification frames*/, AUDIO_SESSION_ALLOCATE,
+                    AudioTrack::TRANSFER_DEFAULT,
+                    nullptr /*offloadInfo*/, -1 /*uid*/, -1 /*pid*/,
+                    mStreamManager->getAttributes());
+
+            oldTrack = mAudioTrack;
+            status = newTrack->initCheck();
+            if (status != NO_ERROR) {
+                ALOGE("%s: error creating AudioTrack", __func__);
+                // newTrack goes out of scope, so reference count drops to zero
+                goto exit;
+            }
+            // From now on, AudioTrack callbacks received with previous toggle value will be ignored.
+            mToggle = toggle;
+            mAudioTrack = newTrack;
+            ALOGV("%s: using new track %p for sound %d",
+                    __func__, newTrack.get(), sound->getSoundID());
+        }
+        if (mMuted) {
+            newTrack->setVolume(0.0f, 0.0f);
+        } else {
+            newTrack->setVolume(leftVolume, rightVolume);
+        }
+        newTrack->setLoop(0, frameCount, loop);
+        mAudioTrack->start();
+        mSound = sound;
+        mSoundID = sound->getSoundID();
+        mPriority = priority;
+        mLoop = loop;
+        mLeftVolume = leftVolume;
+        mRightVolume = rightVolume;
+        mRate = rate;
+        mState = PLAYING;
+        mStopTimeNs = 0;
+        mStreamID = nextStreamID;  // prefer this to be the last, as it is an atomic sync point
+    }
+
+exit:
+    ALOGV("%s: delete oldTrack %p", __func__, oldTrack.get());
+    if (status != NO_ERROR) {
+        // TODO: should we consider keeping the soundID if the old track is OK?
+        // Do not attempt to restart this track (should we remove the stream id?)
+        mState = IDLE;
+        mSoundID = 0;
+        mSound.reset();
+        mAudioTrack.clear();  // actual release from releaseTracks[]
+    }
+}
+
+/* static */
+void Stream::staticCallback(int event, void* user, void* info)
+{
+    const uintptr_t userAsInt = (uintptr_t)user;
+    Stream* stream = reinterpret_cast<Stream*>(userAsInt & ~1);
+    stream->callback(event, info, userAsInt & 1, 0 /* tries */);
+}
+
+void Stream::callback(int event, void* info, int toggle, int tries)
+{
+    ALOGV("%s streamID %d", __func__, (int)mStreamID);
+    int32_t activeStreamIDToRestart = 0;
+    {
+        std::unique_lock lock(mLock);
+
+        if (mAudioTrack == nullptr) {
+            // The AudioTrack is either with this stream or its pair.
+            // if this swaps a few times, the toggle is bound to be wrong, so we fail then.
+            //
+            // TODO: Modify AudioTrack callbacks to avoid the hacky toggle and retry
+            // logic here.
+            if (tries < 3) {
+                lock.unlock();
+                getPairStream()->callback(event, info, toggle, tries + 1);
+            } else {
+                ALOGW("%s streamID %d cannot find track", __func__, (int)mStreamID);
+            }
+            return;
+        }
+        if (mToggle != toggle) {
+            ALOGD("%s streamID %d wrong toggle", __func__, (int)mStreamID);
+            return;
+        }
+        switch (event) {
+        case AudioTrack::EVENT_MORE_DATA:
+            ALOGW("%s streamID %d Invalid EVENT_MORE_DATA for static track",
+                    __func__, (int)mStreamID);
+            break;
+        case AudioTrack::EVENT_UNDERRUN:
+            ALOGW("%s streamID %d Invalid EVENT_UNDERRUN for static track",
+                    __func__, (int)mStreamID);
+            break;
+        case AudioTrack::EVENT_BUFFER_END:
+            ALOGV("%s streamID %d EVENT_BUFFER_END", __func__, (int)mStreamID);
+            if (mState != IDLE) {
+                activeStreamIDToRestart = mStreamID;
+                mStopTimeNs = systemTime();
+            }
+            break;
+        case AudioTrack::EVENT_LOOP_END:
+            ALOGV("%s streamID %d EVENT_LOOP_END", __func__, (int)mStreamID);
+            break;
+        case AudioTrack::EVENT_NEW_IAUDIOTRACK:
+            ALOGV("%s streamID %d NEW_IAUDIOTRACK", __func__, (int)mStreamID);
+            break;
+        default:
+            ALOGW("%s streamID %d Invalid event %d", __func__, (int)mStreamID, event);
+            break;
+        }
+    } // lock ends here.  This is on the callback thread, no need to be precise.
+    if (activeStreamIDToRestart > 0) {
+        // Restart only if a particular streamID is still current and active.
+        ALOGV("%s: moveToRestartQueue %d", __func__, activeStreamIDToRestart);
+        mStreamManager->moveToRestartQueue(this, activeStreamIDToRestart);
+    }
+}
+
+void Stream::dump() const
+{
+    ALOGV("mPairStream=%p, mState=%d, mStreamID=%d, mSoundID=%d, mPriority=%d, mLoop=%d",
+            getPairStream(), mState, (int)mStreamID, mSoundID, mPriority, mLoop);
+}
+
+} // namespace android::soundpool
diff --git a/media/jni/soundpool/Stream.h b/media/jni/soundpool/Stream.h
new file mode 100644
index 0000000..82d2690
--- /dev/null
+++ b/media/jni/soundpool/Stream.h
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "Sound.h"
+
+#include <audio_utils/clock.h>
+#include <media/AudioTrack.h>
+
+namespace android::soundpool {
+
+// This is the amount of time to wait after stop is called when stealing an
+// AudioTrack to allow the sound to ramp down.  If this is 0, glitches
+// may occur when stealing an AudioTrack.
+inline constexpr int64_t kStopWaitTimeNs = 20 * NANOS_PER_MILLISECOND;
+
+inline constexpr size_t kCacheLineSize = 64; /* std::hardware_constructive_interference_size */
+
+class StreamManager; // forward decl
+
+/**
+ * A Stream is associated with a StreamID exposed to the app to play a Sound.
+ *
+ * The Stream uses monitor locking strategy on mLock.
+ * https://en.wikipedia.org/wiki/Monitor_(synchronization)
+ *
+ * where public methods are guarded by a lock (as needed)
+ *
+ * For Java equivalent APIs, see
+ * https://developer.android.com/reference/android/media/SoundPool
+ *
+ * Streams are paired by the StreamManager, so one stream in the pair may be "stopping"
+ * while the other stream of the pair has been prepared to run
+ * (and the streamID returned to the app) pending its pair to be stopped.
+ * The pair of a Stream may be obtained by calling getPairStream(),
+ * where this->getPairStream()->getPairStream() == this; (pair is a commutative relationship).
+ *
+ * playPairStream() and getPairPriority() access the paired stream.
+ * See also StreamManager.h for details of physical layout implications of paired streams.
+ */
+class alignas(kCacheLineSize) Stream {
+public:
+    enum state { IDLE, PAUSED, PLAYING };
+    // The PAUSED, PLAYING state directly corresponds to the AudioTrack state of an active Stream.
+    //
+    // The IDLE state indicates an inactive Stream.   An IDLE Stream may have a non-nullptr
+    // AudioTrack, which may be recycled for use if the SoundID matches the next Stream playback.
+    //
+    // PAUSED -> PLAYING through resume()  (see also autoResume())
+    // PLAYING -> PAUSED through pause()   (see also autoPause())
+    //
+    // IDLE is the initial state of a Stream and also when a stream becomes inactive.
+    // {PAUSED, PLAYING} -> IDLE through stop() (or if the Sound finishes playing)
+    // IDLE -> PLAYING through play().  (there is no way to start a Stream in paused mode).
+
+    ~Stream();
+    void setStreamManager(StreamManager* streamManager) { // non-nullptr
+        mStreamManager = streamManager; // set in StreamManager constructor, not changed
+    }
+
+    // The following methods are monitor locked by mLock.
+    //
+    // For methods taking a streamID:
+    // if the streamID matches the Stream's mStreamID, then method proceeds
+    // else the command is ignored with no effect.
+
+    // returns true if the stream needs to be explicitly stopped.
+    bool requestStop(int32_t streamID);
+    void stop();                    // explicit stop(), typically called from the worker thread.
+    void clearAudioTrack();
+    void pause(int32_t streamID);
+    void autoPause();               // see the Java SoundPool.autoPause documentation for details.
+    void resume(int32_t streamID);
+    void autoResume();
+    void mute(bool muting);
+    void dump() const;
+
+    // returns the pair stream if successful, nullptr otherwise
+    Stream* playPairStream();
+
+    // These parameters are explicitly checked in the SoundPool class
+    // so never deviate from the Java API specified values.
+    void setVolume(int32_t streamID, float leftVolume, float rightVolume);
+    void setRate(int32_t streamID, float rate);
+    void setPriority(int32_t streamID, int priority);
+    void setLoop(int32_t streamID, int loop);
+    void setPlay(int32_t streamID, const std::shared_ptr<Sound> &sound, int32_t soundID,
+           float leftVolume, float rightVolume, int32_t priority, int32_t loop, float rate);
+    void setStopTimeNs(int64_t stopTimeNs); // systemTime() clock monotonic.
+
+    // The following getters are not locked and have weak consistency.
+    // These are considered advisory only - being stale is of nuisance.
+    int32_t getPriority() const { return mPriority; }
+    int32_t getPairPriority() const { return getPairStream()->getPriority(); }
+    int64_t getStopTimeNs() const { return mStopTimeNs; }
+
+    int32_t getStreamID() const { return mStreamID; }  // Can change with setPlay()
+    int32_t getSoundID() const { return mSoundID; }    // Can change with play_l()
+    bool hasSound() const { return mSound.get() != nullptr; }
+
+    Stream* getPairStream() const;  // this never changes.  See top of header.
+
+private:
+    void play_l(const std::shared_ptr<Sound>& sound, int streamID,
+            float leftVolume, float rightVolume, int priority, int loop, float rate,
+            sp<AudioTrack> releaseTracks[2]);
+    void stop_l();
+    void setVolume_l(float leftVolume, float rightVolume);
+
+    // For use with AudioTrack callback.
+    static void staticCallback(int event, void* user, void* info);
+    void callback(int event, void* info, int toggle, int tries);
+
+    // StreamManager should be set on construction and not changed.
+    // release mLock before calling into StreamManager
+    StreamManager*     mStreamManager = nullptr;
+
+    mutable std::mutex  mLock;
+    std::atomic_int32_t mStreamID = 0;          // Note: valid streamIDs are always positive.
+    int                 mState = IDLE;
+    std::shared_ptr<Sound> mSound;              // Non-null if playing.
+    int32_t             mSoundID = 0;           // The sound ID associated with the AudioTrack.
+    float               mLeftVolume = 0.f;
+    float               mRightVolume = 0.f;
+    int32_t             mPriority = INT32_MIN;
+    int32_t             mLoop = 0;
+    float               mRate = 0.f;
+    bool                mAutoPaused = false;
+    bool                mMuted = false;
+
+    sp<AudioTrack>      mAudioTrack;
+    int                 mToggle = 0;
+    int64_t             mStopTimeNs = 0;        // if nonzero, time to wait for stop.
+};
+
+} // namespace android::soundpool
diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp
new file mode 100644
index 0000000..8928c47
--- /dev/null
+++ b/media/jni/soundpool/StreamManager.cpp
@@ -0,0 +1,407 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoundPool::StreamManager"
+#include <utils/Log.h>
+
+#include "StreamManager.h"
+
+#include <audio_utils/clock.h>
+#include <audio_utils/roundup.h>
+
+namespace android::soundpool {
+
+// kMaxStreams is number that should be less than the current AudioTrack max per UID of 40.
+// It is the maximum number of AudioTrack resources allowed in the SoundPool.
+// We suggest a value at least 4 or greater to allow CTS tests to pass.
+static constexpr int32_t kMaxStreams = 32;
+
+// kStealActiveStream_OldestFirst = false historically (Q and earlier)
+// Changing to true could break app expectations but could change behavior beneficially.
+// In R, we change this to true, as it is the correct way per SoundPool documentation.
+static constexpr bool kStealActiveStream_OldestFirst = true;
+
+// kPlayOnCallingThread = true prior to R.
+// Changing to false means calls to play() are almost instantaneous instead of taking around
+// ~10ms to launch the AudioTrack. It is perhaps 100x faster.
+static constexpr bool kPlayOnCallingThread = false;
+
+// Amount of time for a StreamManager thread to wait before closing.
+static constexpr int64_t kWaitTimeBeforeCloseNs = 9 * NANOS_PER_SECOND;
+
+////////////
+
+StreamMap::StreamMap(int32_t streams) {
+    ALOGV("%s(%d)", __func__, streams);
+    if (streams > kMaxStreams) {
+        ALOGW("%s: requested %d streams, clamping to %d", __func__, streams, kMaxStreams);
+        streams = kMaxStreams;
+    } else if (streams < 1) {
+        ALOGW("%s: requested %d streams, clamping to 1", __func__, streams);
+        streams = 1;
+    }
+    mStreamPoolSize = streams * 2;
+    mStreamPool.reset(new Stream[mStreamPoolSize]);
+    // we use a perfect hash table with 2x size to map StreamIDs to Stream pointers.
+    mPerfectHash = std::make_unique<PerfectHash<int32_t, Stream *>>(roundup(mStreamPoolSize * 2));
+}
+
+Stream* StreamMap::findStream(int32_t streamID) const
+{
+    Stream *stream = lookupStreamFromId(streamID);
+    return stream != nullptr && stream->getStreamID() == streamID ? stream : nullptr;
+}
+
+size_t StreamMap::streamPosition(const Stream* stream) const
+{
+    ptrdiff_t index = stream - mStreamPool.get();
+    LOG_ALWAYS_FATAL_IF(index < 0 || index >= mStreamPoolSize,
+            "%s: stream position out of range: %td", __func__, index);
+    return (size_t)index;
+}
+
+Stream* StreamMap::lookupStreamFromId(int32_t streamID) const
+{
+    return streamID > 0 ? mPerfectHash->getValue(streamID).load() : nullptr;
+}
+
+int32_t StreamMap::getNextIdForStream(Stream* stream) const {
+    // even though it is const, it mutates the internal hash table.
+    const int32_t id = mPerfectHash->generateKey(
+        stream,
+        [] (Stream *stream) {
+            return stream == nullptr ? 0 : stream->getStreamID();
+        }, /* getKforV() */
+        stream->getStreamID() /* oldID */);
+    return id;
+}
+
+////////////
+
+StreamManager::StreamManager(
+        int32_t streams, size_t threads, const audio_attributes_t* attributes)
+    : StreamMap(streams)
+    , mAttributes(*attributes)
+{
+    ALOGV("%s(%d, %zu, ...)", __func__, streams, threads);
+    forEach([this](Stream *stream) {
+        stream->setStreamManager(this);
+        if ((streamPosition(stream) & 1) == 0) { // put the first stream of pair as available.
+            mAvailableStreams.insert(stream);
+        }
+    });
+
+    mThreadPool = std::make_unique<ThreadPool>(
+            std::min(threads, (size_t)std::thread::hardware_concurrency()),
+            "SoundPool_");
+}
+
+StreamManager::~StreamManager()
+{
+    ALOGV("%s", __func__);
+    {
+        std::unique_lock lock(mStreamManagerLock);
+        mQuit = true;
+        mStreamManagerCondition.notify_all();
+    }
+    mThreadPool->quit();
+
+    // call stop on the stream pool
+    forEach([](Stream *stream) { stream->stop(); });
+
+    // This invokes the destructor on the AudioTracks -
+    // we do it here to ensure that AudioTrack callbacks will not occur
+    // afterwards.
+    forEach([](Stream *stream) { stream->clearAudioTrack(); });
+}
+
+
+int32_t StreamManager::queueForPlay(const std::shared_ptr<Sound> &sound,
+        int32_t soundID, float leftVolume, float rightVolume,
+        int32_t priority, int32_t loop, float rate)
+{
+    ALOGV("%s(sound=%p, soundID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f)",
+            __func__, sound.get(), soundID, leftVolume, rightVolume, priority, loop, rate);
+    bool launchThread = false;
+    int32_t streamID = 0;
+
+    { // for lock
+        std::unique_lock lock(mStreamManagerLock);
+        Stream *newStream = nullptr;
+        bool fromAvailableQueue = false;
+        ALOGV("%s: mStreamManagerLock lock acquired", __func__);
+
+        sanityCheckQueue_l();
+        // find an available stream, prefer one that has matching sound id.
+        if (mAvailableStreams.size() > 0) {
+            newStream = *mAvailableStreams.begin();
+            for (auto stream : mAvailableStreams) {
+                if (stream->getSoundID() == soundID) {
+                    newStream = stream;
+                    break;
+                }
+            }
+            if (newStream != nullptr) {
+                newStream->setStopTimeNs(systemTime());
+            }
+            fromAvailableQueue = true;
+        }
+
+        // also look in the streams restarting (if the paired stream doesn't have a pending play)
+        if (newStream == nullptr || newStream->getSoundID() != soundID) {
+            for (auto [unused , stream] : mRestartStreams) {
+                if (!stream->getPairStream()->hasSound()) {
+                    if (stream->getSoundID() == soundID) {
+                        newStream = stream;
+                        break;
+                    } else if (newStream == nullptr) {
+                        newStream = stream;
+                    }
+                }
+            }
+        }
+
+        // no available streams, look for one to steal from the active list
+        if (newStream == nullptr) {
+            for (auto stream : mActiveStreams) {
+                if (stream->getPriority() <= priority) {
+                    if (newStream == nullptr
+                            || newStream->getPriority() > stream->getPriority()) {
+                        newStream = stream;
+                    }
+                }
+            }
+            if (newStream != nullptr) { // we need to mute as it is still playing.
+                (void)newStream->requestStop(newStream->getStreamID());
+            }
+        }
+
+        // none found, look for a stream that is restarting, evict one.
+        if (newStream == nullptr) {
+            for (auto [unused, stream] : mRestartStreams) {
+                if (stream->getPairPriority() <= priority) {
+                    newStream = stream;
+                    break;
+                }
+            }
+        }
+
+        // DO NOT LOOK into mProcessingStreams as those are held by the StreamManager threads.
+
+        if (newStream == nullptr) {
+            ALOGD("%s: unable to find stream, returning 0", __func__);
+            return 0; // unable to find available stream
+        }
+
+        Stream *pairStream = newStream->getPairStream();
+        streamID = getNextIdForStream(pairStream);
+        pairStream->setPlay(
+                streamID, sound, soundID, leftVolume, rightVolume, priority, loop, rate);
+        if (fromAvailableQueue && kPlayOnCallingThread) {
+            removeFromQueues_l(newStream);
+            mProcessingStreams.emplace(newStream);
+            lock.unlock();
+            if (Stream* nextStream = newStream->playPairStream()) {
+                lock.lock();
+                ALOGV("%s: starting streamID:%d", __func__, nextStream->getStreamID());
+                addToActiveQueue_l(nextStream);
+            } else {
+                lock.lock();
+                mAvailableStreams.insert(newStream);
+                streamID = 0;
+            }
+            mProcessingStreams.erase(newStream);
+        } else {
+            launchThread = moveToRestartQueue_l(newStream) && needMoreThreads_l();
+        }
+        sanityCheckQueue_l();
+        ALOGV("%s: mStreamManagerLock released", __func__);
+    } // lock
+
+    if (launchThread) {
+        const int32_t id __unused = mThreadPool->launch([this](int32_t id) { run(id); });
+        ALOGV_IF(id != 0, "%s: launched thread %d", __func__, id);
+    }
+    ALOGV("%s: returning %d", __func__, streamID);
+    return streamID;
+}
+
+void StreamManager::moveToRestartQueue(
+        Stream* stream, int32_t activeStreamIDToMatch)
+{
+    ALOGV("%s(stream(ID)=%d, activeStreamIDToMatch=%d)",
+            __func__, stream->getStreamID(), activeStreamIDToMatch);
+    bool restart;
+    {
+        std::lock_guard lock(mStreamManagerLock);
+        sanityCheckQueue_l();
+        if (mProcessingStreams.count(stream) > 0 ||
+                mProcessingStreams.count(stream->getPairStream()) > 0) {
+            ALOGD("%s: attempting to restart processing stream(%d)",
+                    __func__, stream->getStreamID());
+            restart = false;
+        } else {
+            moveToRestartQueue_l(stream, activeStreamIDToMatch);
+            restart = needMoreThreads_l();
+        }
+        sanityCheckQueue_l();
+    }
+    if (restart) {
+        const int32_t id __unused = mThreadPool->launch([this](int32_t id) { run(id); });
+        ALOGV_IF(id != 0, "%s: launched thread %d", __func__, id);
+    }
+}
+
+bool StreamManager::moveToRestartQueue_l(
+        Stream* stream, int32_t activeStreamIDToMatch)
+{
+    ALOGV("%s(stream(ID)=%d, activeStreamIDToMatch=%d)",
+            __func__, stream->getStreamID(), activeStreamIDToMatch);
+    if (activeStreamIDToMatch > 0 && stream->getStreamID() != activeStreamIDToMatch) {
+        return false;
+    }
+    const ssize_t found = removeFromQueues_l(stream, activeStreamIDToMatch);
+    if (found < 0) return false;
+
+    LOG_ALWAYS_FATAL_IF(found > 1, "stream on %zd > 1 stream lists", found);
+
+    addToRestartQueue_l(stream);
+    mStreamManagerCondition.notify_one();
+    return true;
+}
+
+ssize_t StreamManager::removeFromQueues_l(
+        Stream* stream, int32_t activeStreamIDToMatch) {
+    size_t found = 0;
+    for (auto it = mActiveStreams.begin(); it != mActiveStreams.end(); ++it) {
+        if (*it == stream) {
+            mActiveStreams.erase(it); // we erase the iterator and break (otherwise it not safe).
+            ++found;
+            break;
+        }
+    }
+    // activeStreamIDToMatch is nonzero indicates we proceed only if found.
+    if (found == 0 && activeStreamIDToMatch > 0) {
+        return -1;  // special code: not present on active streams, ignore restart request
+    }
+
+    for (auto it = mRestartStreams.begin(); it != mRestartStreams.end(); ++it) {
+        if (it->second == stream) {
+            mRestartStreams.erase(it);
+            ++found;
+            break;
+        }
+    }
+    found += mAvailableStreams.erase(stream);
+
+    // streams on mProcessingStreams are undergoing processing by the StreamManager thread
+    // and do not participate in normal stream migration.
+    return found;
+}
+
+void StreamManager::addToRestartQueue_l(Stream *stream) {
+    mRestartStreams.emplace(stream->getStopTimeNs(), stream);
+}
+
+void StreamManager::addToActiveQueue_l(Stream *stream) {
+    if (kStealActiveStream_OldestFirst) {
+        mActiveStreams.push_back(stream);  // oldest to newest
+    } else {
+        mActiveStreams.push_front(stream); // newest to oldest
+    }
+}
+
+void StreamManager::run(int32_t id)
+{
+    ALOGV("%s(%d) entering", __func__, id);
+    int64_t waitTimeNs = kWaitTimeBeforeCloseNs;
+    std::unique_lock lock(mStreamManagerLock);
+    while (!mQuit) {
+        mStreamManagerCondition.wait_for(
+                lock, std::chrono::duration<int64_t, std::nano>(waitTimeNs));
+        ALOGV("%s(%d) awake", __func__, id);
+
+        sanityCheckQueue_l();
+
+        if (mQuit || (mRestartStreams.empty() && waitTimeNs == kWaitTimeBeforeCloseNs)) {
+            break;  // end the thread
+        }
+
+        waitTimeNs = kWaitTimeBeforeCloseNs;
+        while (!mQuit && !mRestartStreams.empty()) {
+            const nsecs_t nowNs = systemTime();
+            auto it = mRestartStreams.begin();
+            Stream* const stream = it->second;
+            const int64_t diffNs = stream->getStopTimeNs() - nowNs;
+            if (diffNs > 0) {
+                waitTimeNs = std::min(waitTimeNs, diffNs);
+                break;
+            }
+            mRestartStreams.erase(it);
+            mProcessingStreams.emplace(stream);
+            lock.unlock();
+            stream->stop();
+            ALOGV("%s(%d) stopping streamID:%d", __func__, id, stream->getStreamID());
+            if (Stream* nextStream = stream->playPairStream()) {
+                ALOGV("%s(%d) starting streamID:%d", __func__, id, nextStream->getStreamID());
+                lock.lock();
+                if (nextStream->getStopTimeNs() > 0) {
+                    // the next stream was stopped before we can move it to the active queue.
+                    ALOGV("%s(%d) stopping started streamID:%d",
+                            __func__, id, nextStream->getStreamID());
+                    moveToRestartQueue_l(nextStream);
+                } else {
+                    addToActiveQueue_l(nextStream);
+                }
+            } else {
+                lock.lock();
+                mAvailableStreams.insert(stream);
+            }
+            mProcessingStreams.erase(stream);
+            sanityCheckQueue_l();
+        }
+    }
+    ALOGV("%s(%d) exiting", __func__, id);
+}
+
+void StreamManager::dump() const
+{
+    forEach([](const Stream *stream) { stream->dump(); });
+}
+
+void StreamManager::sanityCheckQueue_l() const
+{
+    // We want to preserve the invariant that each stream pair is exactly on one of the queues.
+    const size_t availableStreams = mAvailableStreams.size();
+    const size_t restartStreams = mRestartStreams.size();
+    const size_t activeStreams = mActiveStreams.size();
+    const size_t processingStreams = mProcessingStreams.size();
+    const size_t managedStreams = availableStreams + restartStreams + activeStreams
+                + processingStreams;
+    const size_t totalStreams = getStreamMapSize() >> 1;
+    LOG_ALWAYS_FATAL_IF(managedStreams != totalStreams,
+            "%s: mAvailableStreams:%zu + mRestartStreams:%zu + "
+            "mActiveStreams:%zu + mProcessingStreams:%zu = %zu != total streams %zu",
+            __func__, availableStreams, restartStreams, activeStreams, processingStreams,
+            managedStreams, totalStreams);
+    ALOGV("%s: mAvailableStreams:%zu + mRestartStreams:%zu + "
+            "mActiveStreams:%zu + mProcessingStreams:%zu = %zu (total streams: %zu)",
+            __func__, availableStreams, restartStreams, activeStreams, processingStreams,
+            managedStreams, totalStreams);
+}
+
+} // namespace android::soundpool
diff --git a/media/jni/soundpool/StreamManager.h b/media/jni/soundpool/StreamManager.h
new file mode 100644
index 0000000..8c98ac9
--- /dev/null
+++ b/media/jni/soundpool/StreamManager.h
@@ -0,0 +1,467 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "Stream.h"
+
+#include <condition_variable>
+#include <future>
+#include <list>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <unordered_set>
+#include <vector>
+
+#include <utils/AndroidThreads.h>
+
+namespace android::soundpool {
+
+// TODO: Move helper classes to a utility file, with separate test.
+
+/**
+ * JavaThread is used like std::thread but for threads that may call the JVM.
+ *
+ * std::thread does not easily attach to the JVM.  We need JVM capable threads
+ * from createThreadEtc() since android binder call optimization may attempt to
+ * call back into Java if the SoundPool runs in system server.
+ *
+ *
+ * No locking is required - the member variables are inherently thread-safe.
+ */
+class JavaThread {
+public:
+    JavaThread(std::function<void()> f, const char *name)
+        : mF{std::move(f)} {
+        createThreadEtc(staticFunction, this, name);
+    }
+
+    JavaThread(JavaThread &&) = delete; // uses "this" ptr, not moveable.
+
+    void join() const {
+        mFuture.wait();
+    }
+
+    bool isClosed() const {
+        return mIsClosed;
+    }
+
+private:
+    static int staticFunction(void *data) {
+        JavaThread *jt = static_cast<JavaThread *>(data);
+        jt->mF();
+        jt->mIsClosed = true;
+        jt->mPromise.set_value();
+        return 0;
+    }
+
+    // No locking is provided as these variables are initialized in the constructor
+    // and the members referenced are thread-safe objects.
+    // (mFuture.wait() can block multiple threads.)
+    // Note the order of member variables is reversed for destructor.
+    const std::function<void()> mF;
+    // Used in join() to block until the thread completes.
+    // See https://en.cppreference.com/w/cpp/thread/promise for the void specialization of
+    // promise.
+    std::promise<void>          mPromise;
+    std::future<void>           mFuture{mPromise.get_future()};
+    std::atomic_bool            mIsClosed = false;
+};
+
+/**
+ * The ThreadPool manages thread lifetimes of SoundPool worker threads.
+ *
+ * TODO: the (eventual) goal of ThreadPool is to transparently and cooperatively
+ * maximize CPU utilization while avoiding starvation of other applications.
+ * Some possibilities:
+ *
+ * We should create worker threads when we have SoundPool work and the system is idle.
+ * CPU cycles are "use-it-or-lose-it" when the system is idle.
+ *
+ * We should adjust the priority of worker threads so that the second (and subsequent) worker
+ * threads have lower priority (should we try to promote priority also?).
+ *
+ * We should throttle the spawning of new worker threads, spacing over time, to avoid
+ * creating too many new threads all at once, on initialization.
+ */
+class ThreadPool {
+public:
+    ThreadPool(size_t maxThreadCount, std::string name)
+        : mMaxThreadCount(maxThreadCount)
+        , mName{std::move(name)} { }
+
+    ~ThreadPool() { quit(); }
+
+    size_t getActiveThreadCount() const { return mActiveThreadCount; }
+    size_t getMaxThreadCount() const { return mMaxThreadCount; }
+
+    void quit() {
+        std::list<std::unique_ptr<JavaThread>> threads;
+        {
+            std::lock_guard lock(mThreadLock);
+            if (mQuit) return;  // already joined.
+            mQuit = true;
+            threads = std::move(mThreads);
+            mThreads.clear();
+        }
+        // mQuit set under lock, no more threads will be created.
+        for (auto &thread : threads) {
+            thread->join();
+            thread.reset();
+        }
+        LOG_ALWAYS_FATAL_IF(mActiveThreadCount != 0,
+                "Invalid Active Threads: %zu", (size_t)mActiveThreadCount);
+    }
+
+    // returns a non-zero id if successful, the id is to help logging messages.
+    int32_t launch(std::function<void(int32_t /* id */)> f) {
+        std::list<std::unique_ptr<JavaThread>> threadsToRelease; // release outside of lock.
+        std::lock_guard lock(mThreadLock);
+        if (mQuit) return 0;  // ignore if we have quit
+
+        // clean up threads.
+        for (auto it = mThreads.begin(); it != mThreads.end(); ) {
+            if ((*it)->isClosed()) {
+                threadsToRelease.emplace_back(std::move(*it));
+               it = mThreads.erase(it);
+            } else {
+               ++it;
+            }
+        }
+
+        const size_t threadCount = mThreads.size();
+        if (threadCount < mMaxThreadCount) {
+            // if the id wraps, we don't care about collisions.  it's just for logging.
+            mNextThreadId = mNextThreadId == INT32_MAX ? 1 : ++mNextThreadId;
+            const int32_t id = mNextThreadId;
+            mThreads.emplace_back(std::make_unique<JavaThread>(
+                    [this, id, mf = std::move(f)] { mf(id); --mActiveThreadCount; },
+                    (mName + std::to_string(id)).c_str()));
+            ++mActiveThreadCount;
+            return id;
+        }
+        return 0;
+    }
+
+    // TODO: launch only if load average is low.
+    // This gets the load average
+    // See also std::thread::hardware_concurrency() for the concurrent capability.
+    static double getLoadAvg() {
+        double loadAvg[1];
+        if (getloadavg(loadAvg, std::size(loadAvg)) > 0) {
+            return loadAvg[0];
+        }
+        return -1.;
+    }
+
+private:
+    const size_t            mMaxThreadCount;
+    const std::string       mName;
+
+    std::atomic_size_t      mActiveThreadCount = 0;
+
+    std::mutex              mThreadLock;
+    bool                    mQuit = false;           // GUARDED_BY(mThreadLock)
+    int32_t                 mNextThreadId = 0;       // GUARDED_BY(mThreadLock)
+    std::list<std::unique_ptr<JavaThread>> mThreads; // GUARDED_BY(mThreadLock)
+};
+
+/**
+ * A Perfect HashTable for IDs (key) to pointers (value).
+ *
+ * There are no collisions.  Why? because we generate the IDs for you to look up :-).
+ *
+ * The goal of this hash table is to map an integer ID handle > 0 to a pointer.
+ * We give these IDs in monotonic order (though we may skip if it were to cause a collision).
+ *
+ * The size of the hashtable must be large enough to accommodate the max number of keys.
+ * We suggest 2x.
+ *
+ * Readers are lockless
+ * Single writer could be lockless, but we allow multiple writers through an internal lock.
+ *
+ * For the Key type K, valid keys generated are > 0 (signed or unsigned)
+ * For the Value type V, values are pointers - nullptr means empty.
+ */
+template <typename K, typename V>
+class PerfectHash {
+public:
+    PerfectHash(size_t hashCapacity)
+        : mHashCapacity(hashCapacity)
+        , mK2V{new std::atomic<V>[hashCapacity]()} {
+    }
+
+    // Generate a key for a value V.
+    // There is a testing function getKforV() which checks what the value reports as its key.
+    //
+    // Calls back into getKforV under lock.
+    //
+    // We expect that the hashCapacity is 2x the number of stored keys in order
+    // to have one or two tries to find an empty slot
+    K generateKey(V value, std::function<K(V)> getKforV, K oldKey = 0) {
+        std::lock_guard lock(mHashLock);
+        // try to remove the old key.
+        if (oldKey > 0) {  // key valid
+            const V v = getValue(oldKey);
+            if (v != nullptr) {  // value still valid
+                const K atPosition = getKforV(v);
+                if (atPosition < 0 ||            // invalid value
+                        atPosition == oldKey ||  // value's key still valid and matches old key
+                        ((atPosition ^ oldKey) & (mHashCapacity - 1)) != 0) { // stale key entry
+                    getValue(oldKey) = nullptr;  // invalidate
+                }
+            } // else if value is invalid, no need to invalidate.
+        }
+        // check if we are invalidating only.
+        if (value == nullptr) return 0;
+        // now insert the new value and return the key.
+        size_t tries = 0;
+        for (; tries < mHashCapacity; ++tries) {
+            mNextKey = mNextKey == std::numeric_limits<K>::max() ? 1 : mNextKey + 1;
+            const V v = getValue(mNextKey);
+            //ALOGD("tries: %zu, key:%d value:%p", tries, (int)mNextKey, v);
+            if (v == nullptr) break; // empty
+            const K atPosition = getKforV(v);
+            //ALOGD("tries: %zu  key atPosition:%d", tries, (int)atPosition);
+            if (atPosition < 0 || // invalid value
+                    ((atPosition ^ mNextKey) & (mHashCapacity - 1)) != 0) { // stale key entry
+                break;
+           }
+        }
+        LOG_ALWAYS_FATAL_IF(tries == mHashCapacity, "hash table overflow!");
+        //ALOGD("%s: found after %zu tries", __func__, tries);
+        getValue(mNextKey) = value;
+        return mNextKey;
+    }
+
+    std::atomic<V> &getValue(K key) { return mK2V[key & (mHashCapacity - 1)]; }
+    const std::atomic_int32_t &getValue(K key) const { return mK2V[key & (mHashCapacity - 1)]; }
+
+private:
+    mutable std::mutex          mHashLock;
+    const size_t                mHashCapacity; // size of mK2V no lock needed.
+    std::unique_ptr<std::atomic<V>[]> mK2V;    // no lock needed for read access.
+    K                           mNextKey{};    // GUARDED_BY(mHashLock)
+};
+
+/**
+ * StreamMap contains the all the valid streams available to SoundPool.
+ *
+ * There is no Lock required for this class because the streams are
+ * allocated in the constructor, the lookup is lockless, and the Streams
+ * returned are locked internally.
+ *
+ * The lookup uses a perfect hash.
+ * It is possible to use a lockless hash table or to use a stripe-locked concurrent
+ * hashmap for essentially lock-free lookup.
+ *
+ * This follows Map-Reduce parallelism model.
+ * https://en.wikipedia.org/wiki/MapReduce
+ *
+ * Conceivably the forEach could be parallelized using std::for_each with a
+ * std::execution::par policy.
+ *
+ * https://en.cppreference.com/w/cpp/algorithm/for_each
+ */
+class StreamMap {
+public:
+    explicit StreamMap(int32_t streams);
+
+    // Returns the stream associated with streamID or nullptr if not found.
+    // This need not be locked.
+    // The stream ID will never migrate to another Stream, but it may change
+    // underneath you.  The Stream operations that take a streamID will confirm
+    // that the streamID matches under the Stream lock before executing otherwise
+    // it ignores the command as stale.
+    Stream* findStream(int32_t streamID) const;
+
+    // Iterates through the stream pool applying the function f.
+    // Since this enumerates over every single stream, it is unlocked.
+    //
+    // See related: https://en.cppreference.com/w/cpp/algorithm/for_each
+    void forEach(std::function<void(const Stream *)>f) const {
+        for (size_t i = 0; i < mStreamPoolSize; ++i) {
+            f(&mStreamPool[i]);
+        }
+    }
+
+    void forEach(std::function<void(Stream *)>f) {
+        for (size_t i = 0; i < mStreamPoolSize; ++i) {
+            f(&mStreamPool[i]);
+        }
+    }
+
+    // Returns the pair stream for a given Stream.
+    // This need not be locked as it is a property of the pointer address.
+    Stream* getPairStream(const Stream* stream) const {
+        const size_t index = streamPosition(stream);
+        return &mStreamPool[index ^ 1];
+    }
+
+    // find the position of the stream in mStreamPool array.
+    size_t streamPosition(const Stream* stream) const; // no lock needed
+
+    size_t getStreamMapSize() const {
+        return mStreamPoolSize;
+    }
+
+    // find the next valid ID for a stream and store in hash table.
+    int32_t getNextIdForStream(Stream* stream) const;
+
+private:
+
+    // use the hash table to attempt to find the stream.
+    // nullptr is returned if the lookup fails.
+    Stream* lookupStreamFromId(int32_t streamID) const;
+
+    // The stream pool is initialized in the constructor, effectively const.
+    // no locking required for access.
+    //
+    // The constructor parameter "streams" results in streams pairs of streams.
+    // We have twice as many streams because we wish to return a streamID "handle"
+    // back to the app immediately, while we may be stopping the other stream in the
+    // pair to get its AudioTrack :-).
+    //
+    // Of the stream pair, only one of the streams may have an AudioTrack.
+    // The fixed association of a stream pair allows callbacks from the AudioTrack
+    // to be associated properly to either one or the other of the stream pair.
+    //
+    // TODO: The stream pair arrangement can be removed if we have better AudioTrack
+    // callback handling (being able to remove and change the callback after construction).
+    //
+    // Streams may be accessed anytime off of the stream pool
+    // as there is internal locking on each stream.
+    std::unique_ptr<Stream[]>   mStreamPool;        // no lock needed for access.
+    size_t                      mStreamPoolSize;    // no lock needed for access.
+
+    // In order to find the Stream from a StreamID, we could do a linear lookup in mStreamPool.
+    // As an alternative, one could use stripe-locked or lock-free concurrent hashtables.
+    //
+    // When considering linear search vs hashmap, verify the typical use-case size.
+    // Linear search is faster than std::unordered_map (circa 2018) for less than 40 elements.
+    // [ Skarupke, M. (2018), "You Can Do Better than std::unordered_map: New and Recent
+    // Improvements to Hash Table Performance." C++Now 2018. cppnow.org, see
+    // https://www.youtube.com/watch?v=M2fKMP47slQ ]
+    //
+    // Here, we use a PerfectHash of Id to Stream *, since we can control the
+    // StreamID returned to the user.  This allows O(1) read access to mStreamPool lock-free.
+    //
+    // We prefer that the next stream ID is monotonic for aesthetic reasons
+    // (if we didn't care about monotonicity, a simple method is to apply a generation count
+    // to each stream in the unused upper bits of its index in mStreamPool for the id).
+    //
+    std::unique_ptr<PerfectHash<int32_t, Stream *>> mPerfectHash;
+};
+
+/**
+ * StreamManager is used to manage the streams (accessed by StreamID from Java).
+ *
+ * Locking order (proceeds from application to component).
+ *  SoundPool mApiLock (if needed) -> StreamManager mStreamManagerLock
+ *                                 -> pair Stream mLock -> queued Stream mLock
+ */
+class StreamManager : public StreamMap {
+public:
+    // Note: the SoundPool pointer is only used for stream initialization.
+    // It is not stored in StreamManager.
+    StreamManager(int32_t streams, size_t threads, const audio_attributes_t* attributes);
+    ~StreamManager();
+
+    // Returns positive streamID on success, 0 on failure.  This is locked.
+    int32_t queueForPlay(const std::shared_ptr<Sound> &sound,
+            int32_t soundID, float leftVolume, float rightVolume,
+            int32_t priority, int32_t loop, float rate);
+
+    ///////////////////////////////////////////////////////////////////////
+    // Called from soundpool::Stream
+
+    const audio_attributes_t* getAttributes() const { return &mAttributes; }
+
+    // Moves the stream to the restart queue (called upon BUFFER_END of the static track)
+    // this is locked internally.
+    // If activeStreamIDToMatch is nonzero, it will only move to the restart queue
+    // if the streamIDToMatch is found on the active queue.
+    void moveToRestartQueue(Stream* stream, int32_t activeStreamIDToMatch = 0);
+
+private:
+
+    void run(int32_t id);                        // worker thread, takes lock internally.
+    void dump() const;                           // no lock needed
+
+    // returns true if more worker threads are needed.
+    bool needMoreThreads_l() {
+        return mRestartStreams.size() > 0 &&
+                (mThreadPool->getActiveThreadCount() == 0
+                || std::distance(mRestartStreams.begin(),
+                        mRestartStreams.upper_bound(systemTime()))
+                        > (ptrdiff_t)mThreadPool->getActiveThreadCount());
+    }
+
+    // returns true if the stream was added.
+    bool moveToRestartQueue_l(Stream* stream, int32_t activeStreamIDToMatch = 0);
+    // returns number of queues the stream was removed from (should be 0 or 1);
+    // a special code of -1 is returned if activeStreamIDToMatch is > 0 and
+    // the stream wasn't found on the active queue.
+    ssize_t removeFromQueues_l(Stream* stream, int32_t activeStreamIDToMatch = 0);
+    void addToRestartQueue_l(Stream *stream);
+    void addToActiveQueue_l(Stream *stream);
+    void sanityCheckQueue_l() const;
+
+    const audio_attributes_t mAttributes;
+    std::unique_ptr<ThreadPool> mThreadPool;                  // locked internally
+
+    // mStreamManagerLock is used to lock access for transitions between the
+    // 4 stream queues by the Manager Thread or by the user initiated play().
+    // A stream pair has exactly one stream on exactly one of the queues.
+    std::mutex                  mStreamManagerLock;
+    std::condition_variable     mStreamManagerCondition;
+
+    bool                        mQuit = false;      // GUARDED_BY(mStreamManagerLock)
+
+    // There are constructor arg "streams" pairs of streams, only one of each
+    // pair on the 4 stream queues below.  The other stream in the pair serves as
+    // placeholder to accumulate user changes, pending actual availability of the
+    // AudioTrack, as it may be in use, requiring stop-then-restart.
+    //
+    // The 4 queues are implemented in the appropriate STL container based on perceived
+    // optimality.
+
+    // 1) mRestartStreams: Streams awaiting stop.
+    // The paired stream may be active (but with no AudioTrack), and will be restarted
+    // with an active AudioTrack when the current stream is stopped.
+    std::multimap<int64_t /* stopTimeNs */, Stream*>
+                                mRestartStreams;    // GUARDED_BY(mStreamManagerLock)
+
+    // 2) mActiveStreams: Streams that are active.
+    // The paired stream will be inactive.
+    // This is in order of specified by kStealActiveStream_OldestFirst
+    std::list<Stream*>          mActiveStreams;     // GUARDED_BY(mStreamManagerLock)
+
+    // 3) mAvailableStreams: Streams that are inactive.
+    // The paired stream will also be inactive.
+    // No particular order.
+    std::unordered_set<Stream*> mAvailableStreams;  // GUARDED_BY(mStreamManagerLock)
+
+    // 4) mProcessingStreams: Streams that are being processed by the ManagerThreads
+    // When on this queue, the stream and its pair are not available for stealing.
+    // Each ManagerThread will have at most one stream on the mProcessingStreams queue.
+    // The paired stream may be active or restarting.
+    // No particular order.
+    std::unordered_set<Stream*> mProcessingStreams; // GUARDED_BY(mStreamManagerLock)
+};
+
+} // namespace android::soundpool
diff --git a/media/jni/soundpool/tests/Android.bp b/media/jni/soundpool/tests/Android.bp
new file mode 100644
index 0000000..96ec4e5
--- /dev/null
+++ b/media/jni/soundpool/tests/Android.bp
@@ -0,0 +1,28 @@
+cc_binary {
+    name: "soundpool_stress",
+    host_supported: false,
+
+    include_dirs: [
+        "frameworks/base/media/jni/"
+    ],
+
+    shared_libs: [
+        "libaudioutils",
+        "libbinder",
+        "liblog",
+        "libmedia",
+        "libsoundpool",
+        "libstagefright",
+        "libutils",
+    ],
+
+    srcs: [
+        "soundpool_stress.cpp"
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+}
diff --git a/media/jni/soundpool/tests/build_and_run.sh b/media/jni/soundpool/tests/build_and_run.sh
new file mode 100755
index 0000000..741f2ef
--- /dev/null
+++ b/media/jni/soundpool/tests/build_and_run.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+#
+# Run samples from this directory
+#
+
+if [ -z "$ANDROID_BUILD_TOP" ]; then
+    echo "Android build environment not set"
+    exit -1
+fi
+
+# ensure we have mm
+. $ANDROID_BUILD_TOP/build/envsetup.sh
+
+mm
+
+echo "waiting for device"
+
+adb root && adb wait-for-device remount
+
+echo "========================================"
+echo "testing soundpool_stress"
+uidir="/product/media/audio/notifications"
+adb push $OUT/system/bin/soundpool_stress /system/bin
+
+# test SoundPool playback of all the UI sound samples (loaded twice) looping 10s 1 thread.
+#adb shell /system/bin/soundpool_stress -l -1 $uidir/*.ogg $uidir/*.ogg
+
+# performance test SoundPool playback of all the UI sound samples (x2)
+# 1 iterations, looping, 1 second playback, 4 threads.
+adb shell /system/bin/soundpool_stress -i 1 -l -1 -p 1 -t 4 $uidir/*.ogg $uidir/*.ogg
diff --git a/media/jni/soundpool/tests/soundpool_stress.cpp b/media/jni/soundpool/tests/soundpool_stress.cpp
new file mode 100644
index 0000000..212662f
--- /dev/null
+++ b/media/jni/soundpool/tests/soundpool_stress.cpp
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2014 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 "soundpool"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/stat.h>
+
+#include <atomic>
+#include <future>
+#include <mutex>
+#include <set>
+#include <vector>
+
+#include <audio_utils/clock.h>
+#include <binder/ProcessState.h>
+#include <media/stagefright/MediaExtractorFactory.h>
+#include <soundpool/SoundPool.h> // direct include, this is not an NDK feature.
+#include <system/audio.h>
+#include <utils/Log.h>
+
+using namespace android;
+
+// Errors and diagnostic messages all go to stdout.
+
+namespace {
+
+void usage(const char *name)
+{
+    printf("Usage: %s "
+            "[-i #iterations] [-l #loop] [-p #playback_seconds] [-s #streams] [-t #threads] "
+            "[-z #snoozeSec] <input-file>+\n", name);
+    printf("Uses soundpool to load and play a file (the first 10 seconds)\n");
+    printf("    -i #iterations, default 1\n");
+    printf("    -l #loop looping mode, -1 forever\n");
+    printf("    -p #playback_seconds, default 10\n");
+    printf("    -s #streams for concurrent sound playback, default 20\n");
+    printf("    -t #threads, default 1\n");
+    printf("    -z #snoozeSec after stopping, -1 forever, default 0\n");
+    printf("    <input-file>+ files to be played\n");
+}
+
+std::atomic_int32_t gErrors{};
+std::atomic_int32_t gWarnings{};
+
+void printEvent(const SoundPoolEvent *event) {
+    printf("{ msg:%d  id:%d  status:%d }\n", event->mMsg, event->mArg1, event->mArg2);
+}
+
+class CallbackManager {
+public:
+    int32_t getNumberEvents(int32_t soundID) {
+        std::lock_guard lock(mLock);
+        return mEvents[soundID] > 0;
+    }
+
+    void setSoundPool(SoundPool* soundPool) {
+        std::lock_guard lock(mLock);
+        mSoundPool = soundPool;
+    }
+
+    void callback(SoundPoolEvent event, const SoundPool *soundPool) {
+        std::lock_guard lock(mLock);
+        printEvent(&event);
+        if (soundPool != mSoundPool) {
+            printf("ERROR: mismatched soundpool: %p\n", soundPool);
+            ++gErrors;
+            return;
+        }
+        if (event.mMsg != 1 /* SoundPoolEvent::SOUND_LOADED */) {
+            printf("ERROR: invalid event msg: %d\n", event.mMsg);
+            ++gErrors;
+            return;
+        }
+        if (event.mArg2 != 0) {
+            printf("ERROR: event status(%d) != 0\n", event.mArg2);
+            ++gErrors;
+            return;
+        }
+        if (event.mArg1 <= 0) {
+            printf("ERROR: event soundID(%d) < 0\n", event.mArg1);
+            ++gErrors;
+            return;
+        }
+        ++mEvents[event.mArg1];
+    }
+
+private:
+    std::mutex mLock;
+    SoundPool *mSoundPool = nullptr;
+    std::map<int32_t /* soundID */, int32_t /* count */> mEvents;
+} gCallbackManager;
+
+
+void StaticCallbackManager(SoundPoolEvent event, SoundPool* soundPool, void* user) {
+    ((CallbackManager *)user)->callback(event, soundPool);
+}
+
+void testStreams(SoundPool *soundPool, const std::vector<const char *> &filenames,
+        int loop, int playSec)
+{
+    const int64_t startTimeNs = systemTime();
+    std::vector<int32_t> soundIDs;
+    for (auto filename : filenames) {
+        struct stat st;
+        if (stat(filename, &st) < 0) {
+            printf("ERROR: cannot stat %s\n", filename);
+            return;
+        }
+        const uint64_t length = uint64_t(st.st_size);
+        const int inp = open(filename, O_RDONLY);
+        if (inp < 0) {
+            printf("ERROR: cannot open %s\n", filename);
+            return;
+        }
+        printf("loading (%s) size (%llu)\n", filename, (unsigned long long)length);
+        const int32_t soundID = soundPool->load(
+                inp, 0 /*offset*/, length, 0 /*priority - unused*/);
+        if (soundID == 0) {
+            printf("ERROR: cannot load %s\n", filename);
+            return;
+        }
+        close(inp);
+        soundIDs.emplace_back(soundID);
+        printf("loaded %s soundID(%d)\n", filename, soundID);
+    }
+    const int64_t requestLoadTimeNs = systemTime();
+    printf("\nrequestLoadTimeMs: %d\n",
+            (int)((requestLoadTimeNs - startTimeNs) / NANOS_PER_MILLISECOND));
+
+    // create stream & get Id (playing)
+    const float maxVol = 1.f;
+    const float silentVol = 0.f;
+    const int priority = 0; // lowest
+    const float rate = 1.f;  // normal
+
+    // Loading is done by a SoundPool Worker thread.
+    // TODO: Use SoundPool::setCallback() for wait
+
+    for (int32_t soundID : soundIDs) {
+        while (true) {
+            const int32_t streamID =
+                    soundPool->play(soundID, silentVol, silentVol, priority, 0 /*loop*/, rate);
+            if (streamID != 0) {
+                const int32_t events = gCallbackManager.getNumberEvents(soundID);
+                if (events != 1) {
+                   printf("WARNING: successful play for streamID:%d soundID:%d"
+                          " but callback events(%d) != 1\n", streamID, soundID, events);
+                   ++gWarnings;
+                }
+                soundPool->stop(streamID);
+                break;
+            }
+            usleep(1000);
+        }
+        printf("[%d]", soundID);
+        fflush(stdout);
+    }
+
+    const int64_t loadTimeNs = systemTime();
+    printf("\nloadTimeMs: %d\n", (int)((loadTimeNs - startTimeNs) / NANOS_PER_MILLISECOND));
+
+    // check and play (overlap with above).
+    std::vector<int32_t> streamIDs;
+    for (int32_t soundID : soundIDs) {
+        printf("\nplaying soundID=%d", soundID);
+        const int32_t streamID = soundPool->play(soundID, maxVol, maxVol, priority, loop, rate);
+        if (streamID == 0) {
+            printf(" failed!  ERROR");
+            ++gErrors;
+        } else {
+            printf(" streamID=%d", streamID);
+            streamIDs.emplace_back(streamID);
+        }
+    }
+    const int64_t playTimeNs = systemTime();
+    printf("\nplayTimeMs: %d\n", (int)((playTimeNs - loadTimeNs) / NANOS_PER_MILLISECOND));
+
+    for (int i = 0; i < playSec; ++i) {
+        sleep(1);
+        printf(".");
+        fflush(stdout);
+    }
+
+    for (int32_t streamID : streamIDs) {
+        soundPool->stop(streamID);
+    }
+
+    for (int32_t soundID : soundIDs) {
+        soundPool->unload(soundID);
+    }
+    printf("\nDone!\n");
+}
+
+} // namespace
+
+int main(int argc, char *argv[])
+{
+    const char * const me = argv[0];
+
+    int iterations = 1;
+    int loop = 0;        // disable looping
+    int maxStreams = 40; // change to have more concurrent playback streams
+    int playSec = 10;
+    int snoozeSec = 0;
+    int threadCount = 1;
+    for (int ch; (ch = getopt(argc, argv, "i:l:p:s:t:z:")) != -1; ) {
+        switch (ch) {
+        case 'i':
+            iterations = atoi(optarg);
+            break;
+        case 'l':
+            loop = atoi(optarg);
+            break;
+        case 'p':
+            playSec = atoi(optarg);
+            break;
+        case 's':
+            maxStreams = atoi(optarg);
+            break;
+        case 't':
+            threadCount = atoi(optarg);
+            break;
+        case 'z':
+            snoozeSec = atoi(optarg);
+            break;
+        default:
+            usage(me);
+            return EXIT_FAILURE;
+        }
+    }
+
+    argc -= optind;
+    argv += optind;
+    if (argc <= 0) {
+        usage(me);
+        return EXIT_FAILURE;
+    }
+
+    std::vector<const char *> filenames(argv, argv + argc);
+
+    android::ProcessState::self()->startThreadPool();
+
+    // O and later requires data sniffer registration for proper file type detection
+    MediaExtractorFactory::LoadExtractors();
+
+    // create soundpool
+    audio_attributes_t aa = {
+        .content_type = AUDIO_CONTENT_TYPE_MUSIC,
+        .usage = AUDIO_USAGE_MEDIA,
+    };
+    auto soundPool = std::make_unique<SoundPool>(maxStreams, &aa);
+
+    gCallbackManager.setSoundPool(soundPool.get());
+    soundPool->setCallback(StaticCallbackManager, &gCallbackManager);
+
+    const int64_t startTimeNs = systemTime();
+
+    for (int it = 0; it < iterations; ++it) {
+        // One instance:
+        // testStreams(soundPool.get(), filenames, loop, playSec);
+
+        // Test multiple instances
+        std::vector<std::future<void>> threads(threadCount);
+        printf("testing %zu threads\n", threads.size());
+        for (auto &thread : threads) {
+            thread = std::async(std::launch::async,
+                    [&]{ testStreams(soundPool.get(), filenames, loop, playSec);});
+        }
+        // automatically joins.
+    }
+
+    const int64_t endTimeNs = systemTime();
+
+    // snooze before cleaning up to examine soundpool dumpsys state after stop
+    for (int i = 0; snoozeSec < 0 || i < snoozeSec; ++i) {
+        printf("z");
+        fflush(stdout);
+        sleep(1);
+    };
+
+    gCallbackManager.setSoundPool(nullptr);
+    soundPool.reset();
+
+    printf("total time in ms: %lld\n", (endTimeNs - startTimeNs) / NANOS_PER_MILLISECOND);
+    if (gWarnings != 0) {
+        printf("%d warnings!\n", gWarnings.load());
+    }
+    if (gErrors != 0) {
+        printf("%d errors!\n", gErrors.load());
+        return EXIT_FAILURE;
+    }
+    return EXIT_SUCCESS;
+}
diff --git a/media/lib/signer/Android.bp b/media/lib/signer/Android.bp
index 6b03e4d..3b25787 100644
--- a/media/lib/signer/Android.bp
+++ b/media/lib/signer/Android.bp
@@ -17,7 +17,5 @@
 java_sdk_library {
     name: "com.android.mediadrm.signer",
     srcs: ["java/**/*.java"],
-    api_srcs: [":framework-all-sources"],
-    libs: ["framework-all"],
     api_packages: ["com.android.mediadrm.signer"],
 }
diff --git a/media/native/midi/Android.bp b/media/native/midi/Android.bp
index a0d2050..2da45b6 100644
--- a/media/native/midi/Android.bp
+++ b/media/native/midi/Android.bp
@@ -17,6 +17,7 @@
 
     srcs: [
         "amidi.cpp",
+        "MidiDeviceInfo.cpp",
         ":IMidiDeviceServer.aidl",
     ],
 
@@ -31,12 +32,14 @@
         "-fvisibility=hidden",
     ],
 
+    header_libs: [
+        "media_ndk_headers",
+    ],
+
     shared_libs: [
         "liblog",
         "libbinder",
         "libutils",
-        "libmedia",
-        "libmediandk",
         "libandroid_runtime",
     ],
 
diff --git a/media/native/midi/MidiDeviceInfo.cpp b/media/native/midi/MidiDeviceInfo.cpp
new file mode 100644
index 0000000..ac68d26
--- /dev/null
+++ b/media/native/midi/MidiDeviceInfo.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "MidiDeviceInfo"
+
+#include <MidiDeviceInfo.h>
+
+#include <binder/Parcel.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+#include <utils/String16.h>
+
+namespace android {
+namespace media {
+namespace midi {
+
+// The constant values need to be kept in sync with MidiDeviceInfo.java.
+// static
+const char* const MidiDeviceInfo::PROPERTY_NAME = "name";
+const char* const MidiDeviceInfo::PROPERTY_MANUFACTURER = "manufacturer";
+const char* const MidiDeviceInfo::PROPERTY_PRODUCT = "product";
+const char* const MidiDeviceInfo::PROPERTY_VERSION = "version";
+const char* const MidiDeviceInfo::PROPERTY_SERIAL_NUMBER = "serial_number";
+const char* const MidiDeviceInfo::PROPERTY_ALSA_CARD = "alsa_card";
+const char* const MidiDeviceInfo::PROPERTY_ALSA_DEVICE = "alsa_device";
+
+String16 MidiDeviceInfo::getProperty(const char* propertyName) {
+    String16 value;
+    if (mProperties.getString(String16(propertyName), &value)) {
+        return value;
+    } else {
+        return String16();
+    }
+}
+
+#define RETURN_IF_FAILED(calledOnce)                                     \
+    {                                                                    \
+        status_t returnStatus = calledOnce;                              \
+        if (returnStatus) {                                              \
+            ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \
+            return returnStatus;                                         \
+         }                                                               \
+    }
+
+status_t MidiDeviceInfo::writeToParcel(Parcel* parcel) const {
+    // Needs to be kept in sync with code in MidiDeviceInfo.java
+    RETURN_IF_FAILED(parcel->writeInt32(mType));
+    RETURN_IF_FAILED(parcel->writeInt32(mId));
+    RETURN_IF_FAILED(parcel->writeInt32((int32_t)mInputPortNames.size()));
+    RETURN_IF_FAILED(parcel->writeInt32((int32_t)mOutputPortNames.size()));
+    RETURN_IF_FAILED(writeStringVector(parcel, mInputPortNames));
+    RETURN_IF_FAILED(writeStringVector(parcel, mOutputPortNames));
+    RETURN_IF_FAILED(parcel->writeInt32(mIsPrivate ? 1 : 0));
+    RETURN_IF_FAILED(mProperties.writeToParcel(parcel));
+    // This corresponds to "extra" properties written by Java code
+    RETURN_IF_FAILED(mProperties.writeToParcel(parcel));
+    return OK;
+}
+
+status_t MidiDeviceInfo::readFromParcel(const Parcel* parcel) {
+    // Needs to be kept in sync with code in MidiDeviceInfo.java
+    RETURN_IF_FAILED(parcel->readInt32(&mType));
+    RETURN_IF_FAILED(parcel->readInt32(&mId));
+    int32_t inputPortCount;
+    RETURN_IF_FAILED(parcel->readInt32(&inputPortCount));
+    int32_t outputPortCount;
+    RETURN_IF_FAILED(parcel->readInt32(&outputPortCount));
+    RETURN_IF_FAILED(readStringVector(parcel, &mInputPortNames, inputPortCount));
+    RETURN_IF_FAILED(readStringVector(parcel, &mOutputPortNames, outputPortCount));
+    int32_t isPrivate;
+    RETURN_IF_FAILED(parcel->readInt32(&isPrivate));
+    mIsPrivate = isPrivate == 1;
+    RETURN_IF_FAILED(mProperties.readFromParcel(parcel));
+    // Ignore "extra" properties as they may contain Java Parcelables
+    return OK;
+}
+
+status_t MidiDeviceInfo::readStringVector(
+        const Parcel* parcel, Vector<String16> *vectorPtr, size_t defaultLength) {
+    std::unique_ptr<std::vector<std::unique_ptr<String16>>> v;
+    status_t result = parcel->readString16Vector(&v);
+    if (result != OK) return result;
+    vectorPtr->clear();
+    if (v.get() != nullptr) {
+        for (const auto& iter : *v) {
+            if (iter.get() != nullptr) {
+                vectorPtr->push_back(*iter);
+            } else {
+                vectorPtr->push_back(String16());
+            }
+        }
+    } else {
+        vectorPtr->resize(defaultLength);
+    }
+    return OK;
+}
+
+status_t MidiDeviceInfo::writeStringVector(Parcel* parcel, const Vector<String16>& vector) const {
+    std::vector<String16> v;
+    for (size_t i = 0; i < vector.size(); ++i) {
+        v.push_back(vector[i]);
+    }
+    return parcel->writeString16Vector(v);
+}
+
+// Vector does not define operator==
+static inline bool areVectorsEqual(const Vector<String16>& lhs, const Vector<String16>& rhs) {
+    if (lhs.size() != rhs.size()) return false;
+    for (size_t i = 0; i < lhs.size(); ++i) {
+        if (lhs[i] != rhs[i]) return false;
+    }
+    return true;
+}
+
+bool operator==(const MidiDeviceInfo& lhs, const MidiDeviceInfo& rhs) {
+    return (lhs.mType == rhs.mType && lhs.mId == rhs.mId &&
+            areVectorsEqual(lhs.mInputPortNames, rhs.mInputPortNames) &&
+            areVectorsEqual(lhs.mOutputPortNames, rhs.mOutputPortNames) &&
+            lhs.mProperties == rhs.mProperties &&
+            lhs.mIsPrivate == rhs.mIsPrivate);
+}
+
+}  // namespace midi
+}  // namespace media
+}  // namespace android
diff --git a/media/native/midi/MidiDeviceInfo.h b/media/native/midi/MidiDeviceInfo.h
new file mode 100644
index 0000000..5b4a241
--- /dev/null
+++ b/media/native/midi/MidiDeviceInfo.h
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEDIA_MIDI_DEVICE_INFO_H
+#define ANDROID_MEDIA_MIDI_DEVICE_INFO_H
+
+#include <binder/Parcelable.h>
+#include <binder/PersistableBundle.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace media {
+namespace midi {
+
+class MidiDeviceInfo : public Parcelable {
+public:
+    MidiDeviceInfo() = default;
+    virtual ~MidiDeviceInfo() = default;
+    MidiDeviceInfo(const MidiDeviceInfo& midiDeviceInfo) = default;
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
+
+    int getType() const { return mType; }
+    int getUid() const { return mId; }
+    bool isPrivate() const { return mIsPrivate; }
+    const Vector<String16>& getInputPortNames() const { return mInputPortNames; }
+    const Vector<String16>&  getOutputPortNames() const { return mOutputPortNames; }
+    String16 getProperty(const char* propertyName);
+
+    // The constants need to be kept in sync with MidiDeviceInfo.java
+    enum {
+        TYPE_USB = 1,
+        TYPE_VIRTUAL = 2,
+        TYPE_BLUETOOTH = 3,
+    };
+    static const char* const PROPERTY_NAME;
+    static const char* const PROPERTY_MANUFACTURER;
+    static const char* const PROPERTY_PRODUCT;
+    static const char* const PROPERTY_VERSION;
+    static const char* const PROPERTY_SERIAL_NUMBER;
+    static const char* const PROPERTY_ALSA_CARD;
+    static const char* const PROPERTY_ALSA_DEVICE;
+
+    friend bool operator==(const MidiDeviceInfo& lhs, const MidiDeviceInfo& rhs);
+    friend bool operator!=(const MidiDeviceInfo& lhs, const MidiDeviceInfo& rhs) {
+        return !(lhs == rhs);
+    }
+
+private:
+    status_t readStringVector(
+            const Parcel* parcel, Vector<String16> *vectorPtr, size_t defaultLength);
+    status_t writeStringVector(Parcel* parcel, const Vector<String16>& vector) const;
+
+    int32_t mType;
+    int32_t mId;
+    Vector<String16> mInputPortNames;
+    Vector<String16> mOutputPortNames;
+    os::PersistableBundle mProperties;
+    bool mIsPrivate;
+};
+
+}  // namespace midi
+}  // namespace media
+}  // namespace android
+
+#endif  // ANDROID_MEDIA_MIDI_DEVICE_INFO_H
diff --git a/media/native/midi/amidi.cpp b/media/native/midi/amidi.cpp
index 46f2815..35c4d42 100644
--- a/media/native/midi/amidi.cpp
+++ b/media/native/midi/amidi.cpp
@@ -26,7 +26,7 @@
 #include <core_jni_helpers.h>
 
 #include "android/media/midi/BpMidiDeviceServer.h"
-#include "media/MidiDeviceInfo.h"
+#include "MidiDeviceInfo.h"
 
 #include "include/amidi/AMidi.h"
 #include "amidi_internal.h"
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
index 74bf1a2..de353bf 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
@@ -42,6 +42,7 @@
 
 public class MediaInserterTest extends InstrumentationTestCase {
 
+    private static final String TEST_FEATURE_ID = "testFeature";
     private MediaInserter mMediaInserter;
     private static final int TEST_BUFFER_SIZE = 10;
     private @Mock IContentProvider mMockProvider;
@@ -86,7 +87,8 @@
         MockitoAnnotations.initMocks(this);
 
         final ContentProviderClient client = new ContentProviderClient(
-                getInstrumentation().getContext().getContentResolver(), mMockProvider, true);
+                getInstrumentation().getContext().createFeatureContext(TEST_FEATURE_ID)
+                        .getContentResolver(), mMockProvider, true);
         mMediaInserter = new MediaInserter(client, TEST_BUFFER_SIZE);
         mPackageName = getInstrumentation().getContext().getPackageName();
         mFilesCounter = 0;
@@ -142,31 +144,36 @@
         fillBuffer(sVideoUri, TEST_BUFFER_SIZE - 2);
         fillBuffer(sImagesUri, TEST_BUFFER_SIZE - 1);
 
-        verify(mMockProvider, never()).bulkInsert(eq(mPackageName), any(), any());
+        verify(mMockProvider, never()).bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), any(),
+                any());
     }
 
     @SmallTest
     public void testInsertContentsEqualToBufferSize() throws Exception {
-        when(mMockProvider.bulkInsert(eq(mPackageName), any(), any())).thenReturn(1);
+        when(mMockProvider.bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), any(),
+                any())).thenReturn(1);
 
         fillBuffer(sFilesUri, TEST_BUFFER_SIZE);
         fillBuffer(sAudioUri, TEST_BUFFER_SIZE);
         fillBuffer(sVideoUri, TEST_BUFFER_SIZE);
         fillBuffer(sImagesUri, TEST_BUFFER_SIZE);
 
-        verify(mMockProvider, times(4)).bulkInsert(eq(mPackageName), any(), any());
+        verify(mMockProvider, times(4)).bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), any(),
+                any());
     }
 
     @SmallTest
     public void testInsertContentsMoreThanBufferSize() throws Exception {
-        when(mMockProvider.bulkInsert(eq(mPackageName), any(), any())).thenReturn(1);
+        when(mMockProvider.bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), any(),
+                any())).thenReturn(1);
 
         fillBuffer(sFilesUri, TEST_BUFFER_SIZE + 1);
         fillBuffer(sAudioUri, TEST_BUFFER_SIZE + 2);
         fillBuffer(sVideoUri, TEST_BUFFER_SIZE + 3);
         fillBuffer(sImagesUri, TEST_BUFFER_SIZE + 4);
 
-        verify(mMockProvider, times(4)).bulkInsert(eq(mPackageName), any(), any());
+        verify(mMockProvider, times(4)).bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), any(),
+                any());
     }
 
     @SmallTest
@@ -176,7 +183,8 @@
 
     @SmallTest
     public void testFlushAllWithSomeContents() throws Exception {
-        when(mMockProvider.bulkInsert(eq(mPackageName), any(), any())).thenReturn(1);
+        when(mMockProvider.bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), any(),
+                any())).thenReturn(1);
 
         fillBuffer(sFilesUri, TEST_BUFFER_SIZE - 4);
         fillBuffer(sAudioUri, TEST_BUFFER_SIZE - 3);
@@ -184,12 +192,14 @@
         fillBuffer(sImagesUri, TEST_BUFFER_SIZE - 1);
         mMediaInserter.flushAll();
 
-        verify(mMockProvider, times(4)).bulkInsert(eq(mPackageName), any(), any());
+        verify(mMockProvider, times(4)).bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), any(),
+                any());
     }
 
     @SmallTest
     public void testInsertContentsAfterFlushAll() throws Exception {
-        when(mMockProvider.bulkInsert(eq(mPackageName), any(), any())).thenReturn(1);
+        when(mMockProvider.bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), any(),
+                any())).thenReturn(1);
 
         fillBuffer(sFilesUri, TEST_BUFFER_SIZE - 4);
         fillBuffer(sAudioUri, TEST_BUFFER_SIZE - 3);
@@ -202,15 +212,20 @@
         fillBuffer(sVideoUri, TEST_BUFFER_SIZE + 3);
         fillBuffer(sImagesUri, TEST_BUFFER_SIZE + 4);
 
-        verify(mMockProvider, times(8)).bulkInsert(eq(mPackageName), any(), any());
+        verify(mMockProvider, times(8)).bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), any(),
+                any());
     }
 
     @SmallTest
     public void testInsertContentsWithDifferentSizePerContentType() throws Exception {
-        when(mMockProvider.bulkInsert(eq(mPackageName), eqUri(sFilesUri), any())).thenReturn(1);
-        when(mMockProvider.bulkInsert(eq(mPackageName), eqUri(sAudioUri), any())).thenReturn(1);
-        when(mMockProvider.bulkInsert(eq(mPackageName), eqUri(sVideoUri), any())).thenReturn(1);
-        when(mMockProvider.bulkInsert(eq(mPackageName), eqUri(sImagesUri), any())).thenReturn(1);
+        when(mMockProvider.bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), eqUri(sFilesUri),
+                any())).thenReturn(1);
+        when(mMockProvider.bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), eqUri(sAudioUri),
+                any())).thenReturn(1);
+        when(mMockProvider.bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), eqUri(sVideoUri),
+                any())).thenReturn(1);
+        when(mMockProvider.bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID), eqUri(sImagesUri),
+                any())).thenReturn(1);
 
         for (int i = 0; i < TEST_BUFFER_SIZE; ++i) {
             fillBuffer(sFilesUri, 1);
@@ -219,9 +234,13 @@
             fillBuffer(sImagesUri, 4);
         }
 
-        verify(mMockProvider, times(1)).bulkInsert(eq(mPackageName), eqUri(sFilesUri), any());
-        verify(mMockProvider, times(2)).bulkInsert(eq(mPackageName), eqUri(sAudioUri), any());
-        verify(mMockProvider, times(3)).bulkInsert(eq(mPackageName), eqUri(sVideoUri), any());
-        verify(mMockProvider, times(4)).bulkInsert(eq(mPackageName), eqUri(sImagesUri), any());
+        verify(mMockProvider, times(1)).bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID),
+                eqUri(sFilesUri), any());
+        verify(mMockProvider, times(2)).bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID),
+                eqUri(sAudioUri), any());
+        verify(mMockProvider, times(3)).bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID),
+                eqUri(sVideoUri), any());
+        verify(mMockProvider, times(4)).bulkInsert(eq(mPackageName), eq(TEST_FEATURE_ID),
+                eqUri(sImagesUri), any());
     }
 }
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
index ca43d04..acf8998 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.timeout;
@@ -272,29 +273,28 @@
 
     @Test
     public void testControlVolumeWithRouter() throws Exception {
-        MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
-
         Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CONTROL_CATEGORIES_ALL);
-        mRouter2.registerCallback(mExecutor, mockCallback);
 
         MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
         int originalVolume = volRoute.getVolume();
         int deltaVolume = (originalVolume == volRoute.getVolumeMax() ? -1 : 1);
-        int targetVolume = originalVolume + deltaVolume;
 
-        mRouter2.requestSetVolume(volRoute, targetVolume);
-        verify(mockCallback, timeout(TIMEOUT_MS).atLeastOnce())
-                .onRouteChanged(argThat(route ->
-                        route.getId().equals(volRoute.getId())
-                                && route.getVolume() == targetVolume));
+        CountDownLatch latch1 = new CountDownLatch(1);
+        MediaRouter2.Callback callback1 =
+                createVolumeChangeCallback(ROUTE_ID_VARIABLE_VOLUME,
+                        originalVolume + deltaVolume, latch1);
+        mRouter2.registerCallback(mExecutor, callback1);
+        mRouter2.requestUpdateVolume(volRoute, deltaVolume);
+        assertTrue(latch1.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        mRouter2.unregisterCallback(callback1);
 
-        mRouter2.requestUpdateVolume(volRoute, -deltaVolume);
-        verify(mockCallback, timeout(TIMEOUT_MS).atLeastOnce())
-                .onRouteChanged(argThat(route ->
-                        route.getId().equals(volRoute.getId())
-                                && route.getVolume() == originalVolume));
-
-        mRouter2.unregisterCallback(mockCallback);
+        CountDownLatch latch2 = new CountDownLatch(1);
+        MediaRouter2.Callback callback2 =
+                createVolumeChangeCallback(ROUTE_ID_VARIABLE_VOLUME, originalVolume, latch2);
+        mRouter2.registerCallback(mExecutor, callback2);
+        mRouter2.requestSetVolume(volRoute, originalVolume);
+        assertTrue(latch1.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        mRouter2.unregisterCallback(callback1);
     }
 
     @Test
@@ -312,13 +312,13 @@
         int targetVolume = originalVolume + deltaVolume;
 
         mManager.requestSetVolume(volRoute, targetVolume);
-        verify(mockCallback, timeout(TIMEOUT_MS).atLeastOnce())
+        verify(managerCallback, timeout(TIMEOUT_MS).atLeastOnce())
                 .onRouteChanged(argThat(route ->
                         route.getId().equals(volRoute.getId())
                                 && route.getVolume() == targetVolume));
 
         mManager.requestUpdateVolume(volRoute, -deltaVolume);
-        verify(mockCallback, timeout(TIMEOUT_MS).atLeastOnce())
+        verify(managerCallback, timeout(TIMEOUT_MS).atLeastOnce())
                 .onRouteChanged(argThat(route ->
                         route.getId().equals(volRoute.getId())
                                 && route.getVolume() == originalVolume));
@@ -347,14 +347,14 @@
         CountDownLatch latch = new CountDownLatch(1);
         MediaRouter2.Callback callback = new MediaRouter2.Callback() {
             @Override
-            public void onRoutesChanged(List<MediaRoute2Info> routes) {
-                if (routes.size() > 0) latch.countDown();
+            public void onRoutesAdded(List<MediaRoute2Info> added) {
+                if (added.size() > 0) latch.countDown();
             }
         };
         mRouter2.setControlCategories(controlCategories);
         mRouter2.registerCallback(mExecutor, callback);
         try {
-            latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
             return createRouteMap(mRouter2.getRoutes());
         } finally {
             mRouter2.unregisterCallback(callback);
@@ -370,14 +370,18 @@
         MediaRouter2Manager.Callback managerCallback = new MediaRouter2Manager.Callback() {
             @Override
             public void onRoutesChanged(List<MediaRoute2Info> routes) {
-                if (routes.size() > 0) latch.countDown();
+                if (routes.size() > 0) {
+                    latch.countDown();
+                }
             }
         };
         mManager.registerCallback(mExecutor, managerCallback);
         mRouter2.setControlCategories(controlCategories);
         mRouter2.registerCallback(mExecutor, routerCallback);
         try {
-            latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            //TODO: currently this returns empty list occasionally.
+            //Maybe due to control category is not set yet
             return createRouteMap(mManager.getAvailableRoutes(mPackageName));
         } finally {
             mRouter2.unregisterCallback(routerCallback);
@@ -385,6 +389,20 @@
         }
     }
 
+    MediaRouter2.Callback createVolumeChangeCallback(String routeId,
+            int targetVolume, CountDownLatch latch) {
+        MediaRouter2.Callback callback = new MediaRouter2.Callback() {
+            @Override
+            public void onRoutesChanged(List<MediaRoute2Info> changed) {
+                MediaRoute2Info volRoute = createRouteMap(changed).get(routeId);
+                if (volRoute != null && volRoute.getVolume() == targetVolume) {
+                    latch.countDown();
+                }
+            }
+        };
+        return callback;
+    }
+
     // Helper for getting routes easily
     static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
         Map<String, MediaRoute2Info> routeMap = new HashMap<>();
diff --git a/mime/java-res/android.mime.types b/mime/java-res/android.mime.types
index 7a5299f..ce022a8 100644
--- a/mime/java-res/android.mime.types
+++ b/mime/java-res/android.mime.types
@@ -48,6 +48,9 @@
 ?application/epub+zip epub
 ?application/pkix-cert cer
 ?application/rss+xml rss
+?application/sdp sdp
+?application/smil+xml smil
+?application/ttml+xml ttml dfxp
 ?application/vnd.android.ota ota
 ?application/vnd.apple.mpegurl m3u8
 ?application/vnd.ms-pki.stl stl
@@ -67,12 +70,13 @@
 ?application/x-x509-server-cert crt
 ?application/x-x509-user-cert crt
 
-?audio/3gpp 3gpp
+?audio/3gpp 3gpp 3ga
 ?audio/aac-adts aac
+?audio/ac3 ac3 a52
 ?audio/imelody imy
 ?audio/midi rtttl xmf
 ?audio/mobile-xmf mxmf
-?audio/mp4 m4a
+?audio/mp4 m4a m4b m4p f4a f4b f4p
 ?audio/mpegurl m3u
 ?audio/sp-midi smf
 ?audio/x-matroska mka
@@ -101,10 +105,11 @@
 ?text/xml xml
 ?text/x-vcard vcf
 
-?video/3gpp2 3gpp2 3g2
+?video/3gpp2 3gpp2 3gp2 3g2
 ?video/3gpp 3gpp
 ?video/avi avi
 ?video/m4v m4v
+?video/mp4 m4v f4v mp4v mpeg4
 ?video/mp2p mpeg
 ?video/mp2t m2ts mts
 ?video/mp2ts ts
@@ -129,11 +134,11 @@
 
 application/pgp-signature pgp
 application/x-x509-ca-cert crt
-audio/aac aac
+audio/aac aac adts adt
 audio/basic snd
 audio/flac flac
 audio/midi rtx
-audio/mpeg mp3 m4a m4r
+audio/mpeg mp3 mp2 mp1 mpa m4a m4r
 audio/x-mpegurl m3u m3u8
 image/jpeg jpg
 image/x-ms-bmp bmp
@@ -141,6 +146,6 @@
 text/x-c++hdr hpp
 text/x-c++src cpp
 video/3gpp 3gpp
-video/mpeg mpeg
+video/mpeg mpeg mpeg2 mpv2 mp2v m2v m2t mpeg1 mpv1 mp1v m1v
 video/quicktime mov
 video/x-matroska mkv
diff --git a/native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl b/native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl
index c022388..347e4e8 100644
--- a/native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl
+++ b/native/android/aidl/com/android/internal/compat/IPlatformCompatNative.aidl
@@ -33,9 +33,10 @@
      * you do not need to call this API directly. The change will be reported for you.
      *
      * @param changeId    The ID of the compatibility change taking effect.
+     * @param userId      The ID of the user that the operation is done for.
      * @param packageName The package name of the app in question.
      */
-     void reportChangeByPackageName(long changeId, @utf8InCpp String packageName);
+     void reportChangeByPackageName(long changeId, @utf8InCpp String packageName, int userId);
 
     /**
      * Reports that a compatibility change is affecting an app process now.
@@ -64,9 +65,10 @@
      *
      * @param changeId    The ID of the compatibility change in question.
      * @param packageName The package name of the app in question.
+     * @param userId      The ID of the user that the operation is done for.
      * @return {@code true} if the change is enabled for the current app.
      */
-    boolean isChangeEnabledByPackageName(long changeId, @utf8InCpp String packageName);
+    boolean isChangeEnabledByPackageName(long changeId, @utf8InCpp String packageName, int userId);
 
     /**
      * Query if a given compatibility change is enabled for an app process. This method should
diff --git a/native/android/system_fonts.cpp b/native/android/system_fonts.cpp
index 9791da6..45f42f1b5 100644
--- a/native/android/system_fonts.cpp
+++ b/native/android/system_fonts.cpp
@@ -16,6 +16,8 @@
 
 #include <jni.h>
 
+#define LOG_TAG "SystemFont"
+
 #include <android/font.h>
 #include <android/font_matcher.h>
 #include <android/system_fonts.h>
@@ -47,9 +49,14 @@
 using XmlCharUniquePtr = std::unique_ptr<xmlChar, XmlCharDeleter>;
 using XmlDocUniquePtr = std::unique_ptr<xmlDoc, XmlDocDeleter>;
 
+struct ParserState {
+    xmlNode* mFontNode = nullptr;
+    XmlCharUniquePtr mLocale;
+};
+
 struct ASystemFontIterator {
     XmlDocUniquePtr mXmlDoc;
-    xmlNode* mFontNode;
+    ParserState state;
 
     // The OEM customization XML.
     XmlDocUniquePtr mCustomizationXmlDoc;
@@ -97,6 +104,7 @@
 
 const xmlChar* FAMILY_TAG = BAD_CAST("family");
 const xmlChar* FONT_TAG = BAD_CAST("font");
+const xmlChar* LOCALE_ATTR_NAME = BAD_CAST("lang");
 
 xmlNode* firstElement(xmlNode* node, const xmlChar* tag) {
     for (xmlNode* child = node->children; child; child = child->next) {
@@ -116,9 +124,9 @@
     return nullptr;
 }
 
-void copyFont(const XmlDocUniquePtr& xmlDoc, xmlNode* fontNode, AFont* out,
+void copyFont(const XmlDocUniquePtr& xmlDoc, const ParserState& state, AFont* out,
               const std::string& pathPrefix) {
-    const xmlChar* LOCALE_ATTR_NAME = BAD_CAST("lang");
+    xmlNode* fontNode = state.mFontNode;
     XmlCharUniquePtr filePathStr(
             xmlNodeListGetString(xmlDoc.get(), fontNode->xmlChildrenNode, 1));
     out->mFilePath = pathPrefix + xmlTrim(
@@ -139,9 +147,10 @@
     out->mCollectionIndex =  indexStr ?
             strtol(reinterpret_cast<const char*>(indexStr.get()), nullptr, 10) : 0;
 
-    XmlCharUniquePtr localeStr(xmlGetProp(xmlDoc->parent, LOCALE_ATTR_NAME));
     out->mLocale.reset(
-            localeStr ? new std::string(reinterpret_cast<const char*>(localeStr.get())) : nullptr);
+            state.mLocale ?
+            new std::string(reinterpret_cast<const char*>(state.mLocale.get()))
+            : nullptr);
 
     const xmlChar* TAG_ATTR_NAME = BAD_CAST("tag");
     const xmlChar* STYLEVALUE_ATTR_NAME = BAD_CAST("stylevalue");
@@ -178,25 +187,27 @@
     return S_ISREG(st.st_mode);
 }
 
-xmlNode* findFirstFontNode(const XmlDocUniquePtr& doc) {
+bool findFirstFontNode(const XmlDocUniquePtr& doc, ParserState* state) {
     xmlNode* familySet = xmlDocGetRootElement(doc.get());
     if (familySet == nullptr) {
-        return nullptr;
+        return false;
     }
     xmlNode* family = firstElement(familySet, FAMILY_TAG);
     if (family == nullptr) {
-        return nullptr;
+        return false;
     }
+    state->mLocale.reset(xmlGetProp(family, LOCALE_ATTR_NAME));
 
     xmlNode* font = firstElement(family, FONT_TAG);
     while (font == nullptr) {
         family = nextSibling(family, FAMILY_TAG);
         if (family == nullptr) {
-            return nullptr;
+            return false;
         }
         font = firstElement(family, FONT_TAG);
     }
-    return font;
+    state->mFontNode = font;
+    return font != nullptr;
 }
 
 }  // namespace
@@ -272,38 +283,38 @@
     return result.release();
 }
 
-xmlNode* findNextFontNode(const XmlDocUniquePtr& xmlDoc, xmlNode* fontNode) {
-    if (fontNode == nullptr) {
+bool findNextFontNode(const XmlDocUniquePtr& xmlDoc, ParserState* state) {
+    if (state->mFontNode == nullptr) {
         if (!xmlDoc) {
-            return nullptr;  // Already at the end.
+            return false;  // Already at the end.
         } else {
             // First time to query font.
-            return findFirstFontNode(xmlDoc);
+            return findFirstFontNode(xmlDoc, state);
         }
     } else {
-        xmlNode* nextNode = nextSibling(fontNode, FONT_TAG);
+        xmlNode* nextNode = nextSibling(state->mFontNode, FONT_TAG);
         while (nextNode == nullptr) {
-            xmlNode* family = nextSibling(fontNode->parent, FAMILY_TAG);
+            xmlNode* family = nextSibling(state->mFontNode->parent, FAMILY_TAG);
             if (family == nullptr) {
                 break;
             }
+            state->mLocale.reset(xmlGetProp(family, LOCALE_ATTR_NAME));
             nextNode = firstElement(family, FONT_TAG);
         }
-        return nextNode;
+        state->mFontNode = nextNode;
+        return nextNode != nullptr;
     }
 }
 
 AFont* ASystemFontIterator_next(ASystemFontIterator* ite) {
     LOG_ALWAYS_FATAL_IF(ite == nullptr, "nullptr has passed as iterator argument");
     if (ite->mXmlDoc) {
-        ite->mFontNode = findNextFontNode(ite->mXmlDoc, ite->mFontNode);
-        if (ite->mFontNode == nullptr) {
+        if (!findNextFontNode(ite->mXmlDoc, &ite->state)) {
             // Reached end of the XML file. Continue OEM customization.
             ite->mXmlDoc.reset();
-            ite->mFontNode = nullptr;
         } else {
             std::unique_ptr<AFont> font = std::make_unique<AFont>();
-            copyFont(ite->mXmlDoc, ite->mFontNode, font.get(), "/system/fonts/");
+            copyFont(ite->mXmlDoc, ite->state, font.get(), "/system/fonts/");
             if (!isFontFileAvailable(font->mFilePath)) {
                 return ASystemFontIterator_next(ite);
             }
@@ -312,15 +323,13 @@
     }
     if (ite->mCustomizationXmlDoc) {
         // TODO: Filter only customizationType="new-named-family"
-        ite->mFontNode = findNextFontNode(ite->mCustomizationXmlDoc, ite->mFontNode);
-        if (ite->mFontNode == nullptr) {
+        if (!findNextFontNode(ite->mCustomizationXmlDoc, &ite->state)) {
             // Reached end of the XML file. Finishing
             ite->mCustomizationXmlDoc.reset();
-            ite->mFontNode = nullptr;
             return nullptr;
         } else {
             std::unique_ptr<AFont> font = std::make_unique<AFont>();
-            copyFont(ite->mCustomizationXmlDoc, ite->mFontNode, font.get(), "/product/fonts/");
+            copyFont(ite->mCustomizationXmlDoc, ite->state, font.get(), "/product/fonts/");
             if (!isFontFileAvailable(font->mFilePath)) {
                 return ASystemFontIterator_next(ite);
             }
@@ -351,7 +360,7 @@
 
 const char* AFont_getLocale(const AFont* font) {
     LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument");
-    return font->mLocale ? nullptr : font->mLocale->c_str();
+    return font->mLocale ? font->mLocale->c_str() : nullptr;
 }
 
 size_t AFont_getCollectionIndex(const AFont* font) {
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 672879a..b2451c9 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -63,6 +63,64 @@
 
 }
 
+android_library {
+    name: "CarSystemUI-tests",
+    manifest: "tests/AndroidManifest.xml",
+    resource_dirs: [
+        "tests/res",
+        "res-keyguard",
+        "res",
+    ],
+    srcs: [
+        "tests/src/**/*.java",
+        "src/**/*.java",
+        "src/**/I*.aidl",
+    ],
+    static_libs: [
+        "SystemUI-tests",
+        "CarNotificationLib",
+        "SystemUIPluginLib",
+        "SystemUISharedLib",
+        "SettingsLib",
+        "android.car.userlib",
+        "androidx.legacy_legacy-support-v4",
+        "androidx.recyclerview_recyclerview",
+        "androidx.preference_preference",
+        "androidx.appcompat_appcompat",
+        "androidx.mediarouter_mediarouter",
+        "androidx.palette_palette",
+        "androidx.legacy_legacy-preference-v14",
+        "androidx.leanback_leanback",
+        "androidx.slice_slice-core",
+        "androidx.slice_slice-view",
+        "androidx.slice_slice-builders",
+        "androidx.arch.core_core-runtime",
+        "androidx.lifecycle_lifecycle-extensions",
+        "SystemUI-tags",
+        "SystemUI-proto",
+        "metrics-helper-lib",
+        "androidx.test.rules", "hamcrest-library",
+        "mockito-target-inline-minus-junit4",
+        "testables",
+        "truth-prebuilt",
+        "dagger2-2.19",
+        "//external/kotlinc:kotlin-annotations",
+    ],
+    libs: [
+        "android.test.runner",
+        "telephony-common",
+        "android.test.base",
+        "android.car",
+    ],
+
+    aaptflags: [
+        "--extra-packages",
+        "com.android.systemui",
+    ],
+
+    plugins: ["dagger2-compiler-2.19"],
+}
+
 android_app {
     name: "CarSystemUI",
 
diff --git a/packages/CarSystemUI/res/layout/car_navigation_bar_unprovisioned.xml b/packages/CarSystemUI/res/layout/car_navigation_bar_unprovisioned.xml
index 1cf48c5..0f964fd 100644
--- a/packages/CarSystemUI/res/layout/car_navigation_bar_unprovisioned.xml
+++ b/packages/CarSystemUI/res/layout/car_navigation_bar_unprovisioned.xml
@@ -31,14 +31,15 @@
         android:paddingStart="@*android:dimen/car_padding_5"
         android:paddingEnd="@*android:dimen/car_padding_5">
 
-        <com.android.systemui.navigationbar.car.CarNavigationButton
+        <com.android.systemui.navigationbar.car.CarFacetButton
             android:id="@+id/home"
             android:layout_width="@*android:dimen/car_touch_target_size"
             android:layout_height="match_parent"
             android:background="?android:attr/selectableItemBackground"
-            android:src="@drawable/car_ic_overview"
+            systemui:icon="@drawable/car_ic_overview"
             systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
-        />
+            systemui:selectedIcon="@drawable/car_ic_overview_selected"
+            systemui:useMoreIcon="false"/>
     </LinearLayout>
 </com.android.systemui.navigationbar.car.CarNavigationBarView>
 
diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml
index fe042fe..981c129 100644
--- a/packages/CarSystemUI/res/values/config.xml
+++ b/packages/CarSystemUI/res/values/config.xml
@@ -40,10 +40,24 @@
          slots that may be reused for things like IME control. -->
     <integer name="config_maxNotificationIcons">0</integer>
 
+    <!--
+        Initial alpha percent value for the background when the notification
+        shade is open. Should be a number between, and inclusive, 0 and 100.
+        If the number is 0, then the background alpha starts off fully
+        transparent. If the number if 100, then the background alpha starts off
+        fully opaque. -->
+    <integer name="config_initialNotificationBackgroundAlpha">0</integer>
+    <!--
+        Final alpha percent value for the background when the notification
+        shade is fully open. Should be a number between, and inclusive, 0 and
+        100. If this value is smaller than
+        config_initialNotificationBackgroundAlpha, the background will default
+        to a constant alpha percent value using the initial alpha. -->
+    <integer name="config_finalNotificationBackgroundAlpha">100</integer>
+
     <!-- SystemUI Services: The classes of the stuff to start. -->
     <string-array name="config_systemUIServiceComponents" translatable="false">
         <item>com.android.systemui.util.NotificationChannels</item>
-        <item>com.android.systemui.statusbar.CommandQueue$CommandQueueStart</item>
         <item>com.android.systemui.keyguard.KeyguardViewMediator</item>
         <item>com.android.systemui.recents.Recents</item>
         <item>com.android.systemui.volume.VolumeUI</item>
diff --git a/packages/CarSystemUI/res/values/integers_car.xml b/packages/CarSystemUI/res/values/integers_car.xml
index fb67b30..d6c16cb 100644
--- a/packages/CarSystemUI/res/values/integers_car.xml
+++ b/packages/CarSystemUI/res/values/integers_car.xml
@@ -34,4 +34,7 @@
     <!-- The delay before the unlock dialog pops up -->
     <integer name="unlock_dialog_delay_ms">0</integer>
 
+    <!-- Timeout values in milliseconds for displaying volume dialog-->
+    <integer name="car_volume_dialog_display_normal_timeout">3000</integer>
+    <integer name="car_volume_dialog_display_hovering_timeout">16000</integer>
 </resources>
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarComponentBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarComponentBinder.java
new file mode 100644
index 0000000..f11eff8
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/CarComponentBinder.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+import com.android.systemui.dagger.DefaultActivityBinder;
+import com.android.systemui.dagger.DefaultBroadcastReceiverBinder;
+import com.android.systemui.dagger.DefaultServiceBinder;
+
+import dagger.Module;
+
+/**
+ * Supply Activities, Services, and SystemUI Objects for CarSystemUI.
+ */
+@Module(includes = {
+        DefaultActivityBinder.class,
+        DefaultBroadcastReceiverBinder.class,
+        DefaultServiceBinder.class,
+        CarSystemUIBinder.class})
+public class CarComponentBinder {
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
index 8e0a3eb..706727b 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
@@ -16,19 +16,350 @@
 
 package com.android.systemui;
 
+import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
+
+import android.content.Context;
+import android.os.PowerManager;
+import android.util.DisplayMetrics;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.appops.AppOpsController;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.doze.DozeLog;
+import com.android.systemui.globalactions.GlobalActionsComponent;
+import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.navigationbar.car.CarNavigationBar;
+import com.android.systemui.navigationbar.car.CarNavigationBarController;
+import com.android.systemui.pip.PipUI;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.power.PowerUI;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsModule;
+import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.statusbar.NavigationBarController;
+import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationViewHierarchyManager;
+import com.android.systemui.statusbar.PulseExpansionHandler;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.car.CarStatusBar;
+import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
+import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.InstantAppNotifier;
+import com.android.systemui.statusbar.notification.NewNotifPipeline;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+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.logging.NotifLog;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.phone.AutoHideController;
+import com.android.systemui.statusbar.phone.BiometricUnlockController;
+import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.phone.DozeScrimController;
+import com.android.systemui.statusbar.phone.DozeServiceHost;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.LightBarController;
+import com.android.systemui.statusbar.phone.LockscreenWallpaper;
+import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.StatusBarWindowController;
+import com.android.systemui.statusbar.phone.StatusBarWindowViewController;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
+import com.android.systemui.statusbar.policy.RemoteInputUriController;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.tv.TvStatusBar;
+import com.android.systemui.theme.ThemeOverlayController;
+import com.android.systemui.util.InjectionInflationController;
+import com.android.systemui.util.leak.GarbageMonitor;
+import com.android.systemui.volume.VolumeUI;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import dagger.Binds;
+import dagger.Lazy;
 import dagger.Module;
+import dagger.Provides;
 import dagger.multibindings.ClassKey;
 import dagger.multibindings.IntoMap;
 
 /** Binder for car specific {@link SystemUI} modules. */
-@Module
+@Module(includes = {RecentsModule.class})
 public abstract class CarSystemUIBinder {
+    /** Inject into AuthController. */
+    @Binds
+    @IntoMap
+    @ClassKey(AuthController.class)
+    public abstract SystemUI bindAuthController(AuthController service);
+
     /** */
     @Binds
     @IntoMap
     @ClassKey(CarNavigationBar.class)
     public abstract SystemUI bindCarNavigationBar(CarNavigationBar sysui);
+
+    /** Inject into GarbageMonitor.Service. */
+    @Binds
+    @IntoMap
+    @ClassKey(GarbageMonitor.Service.class)
+    public abstract SystemUI bindGarbageMonitorService(GarbageMonitor.Service service);
+
+    /** Inject into GlobalActionsComponent. */
+    @Binds
+    @IntoMap
+    @ClassKey(GlobalActionsComponent.class)
+    public abstract SystemUI bindGlobalActionsComponent(GlobalActionsComponent sysui);
+
+    /** Inject into InstantAppNotifier. */
+    @Binds
+    @IntoMap
+    @ClassKey(InstantAppNotifier.class)
+    public abstract SystemUI bindInstantAppNotifier(InstantAppNotifier sysui);
+
+    /** Inject into KeyguardViewMediator. */
+    @Binds
+    @IntoMap
+    @ClassKey(KeyguardViewMediator.class)
+    public abstract SystemUI bindKeyguardViewMediator(KeyguardViewMediator sysui);
+
+    /** Inject into LatencyTests. */
+    @Binds
+    @IntoMap
+    @ClassKey(LatencyTester.class)
+    public abstract SystemUI bindLatencyTester(LatencyTester sysui);
+
+    /** Inject into PipUI. */
+    @Binds
+    @IntoMap
+    @ClassKey(PipUI.class)
+    public abstract SystemUI bindPipUI(PipUI sysui);
+
+    /** Inject into PowerUI. */
+    @Binds
+    @IntoMap
+    @ClassKey(PowerUI.class)
+    public abstract SystemUI bindPowerUI(PowerUI sysui);
+
+    /** Inject into Recents. */
+    @Binds
+    @IntoMap
+    @ClassKey(Recents.class)
+    public abstract SystemUI bindRecents(Recents sysui);
+
+    /** Inject into ScreenDecorations. */
+    @Binds
+    @IntoMap
+    @ClassKey(ScreenDecorations.class)
+    public abstract SystemUI bindScreenDecorations(ScreenDecorations sysui);
+
+    /** Inject into SizeCompatModeActivityController. */
+    @Binds
+    @IntoMap
+    @ClassKey(SizeCompatModeActivityController.class)
+    public abstract SystemUI bindsSizeCompatModeActivityController(
+            SizeCompatModeActivityController sysui);
+
+    /** Inject into SliceBroadcastRelayHandler. */
+    @Binds
+    @IntoMap
+    @ClassKey(SliceBroadcastRelayHandler.class)
+    public abstract SystemUI bindSliceBroadcastRelayHandler(SliceBroadcastRelayHandler sysui);
+
+    /** Inject into ThemeOverlayController. */
+    @Binds
+    @IntoMap
+    @ClassKey(ThemeOverlayController.class)
+    public abstract SystemUI bindThemeOverlayController(ThemeOverlayController sysui);
+
+    /** Inject into StatusBar. */
+    @Binds
+    @IntoMap
+    @ClassKey(StatusBar.class)
+    public abstract SystemUI bindsStatusBar(CarStatusBar sysui);
+
+    /** Inject into TvStatusBar. */
+    @Binds
+    @IntoMap
+    @ClassKey(TvStatusBar.class)
+    public abstract SystemUI bindsTvStatusBar(TvStatusBar sysui);
+
+    /** Inject into StatusBarGoogle. */
+    @Binds
+    @IntoMap
+    @ClassKey(CarStatusBar.class)
+    public abstract SystemUI bindsCarStatusBar(CarStatusBar sysui);
+
+    /** Inject into VolumeUI. */
+    @Binds
+    @IntoMap
+    @ClassKey(VolumeUI.class)
+    public abstract SystemUI bindVolumeUI(VolumeUI sysui);
+
+    /**
+     * Provides our instance of StatusBar which is considered optional.
+     */
+    @Provides
+    @Singleton
+    static CarStatusBar provideStatusBar(
+            Context context,
+            FeatureFlags featureFlags,
+            LightBarController lightBarController,
+            AutoHideController autoHideController,
+            KeyguardUpdateMonitor keyguardUpdateMonitor,
+            StatusBarIconController statusBarIconController,
+            DozeLog dozeLog,
+            InjectionInflationController injectionInflationController,
+            PulseExpansionHandler pulseExpansionHandler,
+            NotificationWakeUpCoordinator notificationWakeUpCoordinator,
+            KeyguardBypassController keyguardBypassController,
+            KeyguardStateController keyguardStateController,
+            HeadsUpManagerPhone headsUpManagerPhone,
+            DynamicPrivacyController dynamicPrivacyController,
+            BypassHeadsUpNotifier bypassHeadsUpNotifier,
+            @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowNotificationLongPress,
+            Lazy<NewNotifPipeline> newNotifPipeline,
+            FalsingManager falsingManager,
+            BroadcastDispatcher broadcastDispatcher,
+            RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
+            NotificationGutsManager notificationGutsManager,
+            NotificationLogger notificationLogger,
+            NotificationEntryManager notificationEntryManager,
+            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+            NotificationViewHierarchyManager notificationViewHierarchyManager,
+            ForegroundServiceController foregroundServiceController,
+            AppOpsController appOpsController,
+            KeyguardViewMediator keyguardViewMediator,
+            ZenModeController zenModeController,
+            NotificationAlertingManager notificationAlertingManager,
+            DisplayMetrics displayMetrics,
+            MetricsLogger metricsLogger,
+            UiOffloadThread uiOffloadThread,
+            NotificationMediaManager notificationMediaManager,
+            NotificationLockscreenUserManager lockScreenUserManager,
+            NotificationRemoteInputManager remoteInputManager,
+            UserSwitcherController userSwitcherController,
+            NetworkController networkController,
+            BatteryController batteryController,
+            SysuiColorExtractor colorExtractor,
+            ScreenLifecycle screenLifecycle,
+            WakefulnessLifecycle wakefulnessLifecycle,
+            SysuiStatusBarStateController statusBarStateController,
+            VibratorHelper vibratorHelper,
+            BubbleController bubbleController,
+            NotificationGroupManager groupManager,
+            NotificationGroupAlertTransferHelper groupAlertTransferHelper,
+            VisualStabilityManager visualStabilityManager,
+            DeviceProvisionedController deviceProvisionedController,
+            NavigationBarController navigationBarController,
+            AssistManager assistManager,
+            NotificationListener notificationListener,
+            ConfigurationController configurationController,
+            StatusBarWindowController statusBarWindowController,
+            StatusBarWindowViewController.Builder statusBarWindowViewControllerBuilder,
+            NotifLog notifLog,
+            DozeParameters dozeParameters,
+            ScrimController scrimController,
+            Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
+            Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
+            DozeServiceHost dozeServiceHost,
+            PowerManager powerManager,
+            DozeScrimController dozeScrimController,
+            CommandQueue commandQueue,
+            PluginManager pluginManager,
+            CarNavigationBarController carNavigationBarController,
+            RemoteInputUriController remoteInputUriController) {
+        return new CarStatusBar(
+                context,
+                featureFlags,
+                lightBarController,
+                autoHideController,
+                keyguardUpdateMonitor,
+                statusBarIconController,
+                dozeLog,
+                injectionInflationController,
+                pulseExpansionHandler,
+                notificationWakeUpCoordinator,
+                keyguardBypassController,
+                keyguardStateController,
+                headsUpManagerPhone,
+                dynamicPrivacyController,
+                bypassHeadsUpNotifier,
+                allowNotificationLongPress,
+                newNotifPipeline,
+                falsingManager,
+                broadcastDispatcher,
+                remoteInputQuickSettingsDisabler,
+                notificationGutsManager,
+                notificationLogger,
+                notificationEntryManager,
+                notificationInterruptionStateProvider,
+                notificationViewHierarchyManager,
+                foregroundServiceController,
+                appOpsController,
+                keyguardViewMediator,
+                zenModeController,
+                notificationAlertingManager,
+                displayMetrics,
+                metricsLogger,
+                uiOffloadThread,
+                notificationMediaManager,
+                lockScreenUserManager,
+                remoteInputManager,
+                userSwitcherController,
+                networkController,
+                batteryController,
+                colorExtractor,
+                screenLifecycle,
+                wakefulnessLifecycle,
+                statusBarStateController,
+                vibratorHelper,
+                bubbleController,
+                groupManager,
+                groupAlertTransferHelper,
+                visualStabilityManager,
+                deviceProvisionedController,
+                navigationBarController,
+                assistManager,
+                notificationListener,
+                configurationController,
+                statusBarWindowController,
+                statusBarWindowViewControllerBuilder,
+                notifLog,
+                dozeParameters,
+                scrimController,
+                lockscreenWallpaperLazy,
+                biometricUnlockControllerLazy,
+                dozeServiceHost,
+                powerManager,
+                dozeScrimController,
+                commandQueue,
+                pluginManager,
+                remoteInputUriController,
+                carNavigationBarController);
+    }
 }
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index 0f44e08..d3a6cde 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -46,8 +46,6 @@
 import dagger.Binds;
 import dagger.Module;
 import dagger.Provides;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.IntoMap;
 
 @Module
 abstract class CarSystemUIModule {
@@ -102,9 +100,7 @@
             CarSystemUIRootComponent systemUIRootComponent);
 
     @Binds
-    @IntoMap
-    @ClassKey(StatusBar.class)
-    public abstract SystemUI providesStatusBar(CarStatusBar statusBar);
+    public abstract StatusBar bindStatusBar(CarStatusBar statusBar);
 
     @Binds
     abstract VolumeDialogComponent bindVolumeDialogComponent(
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java
index c2847c8..51b263e 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java
@@ -29,6 +29,7 @@
 @Singleton
 @Component(
         modules = {
+                CarComponentBinder.class,
                 DependencyProvider.class,
                 DependencyBinder.class,
                 SystemUIFactory.ContextHolder.class,
diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
index 6fba1d5..af92767 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java
@@ -37,8 +37,6 @@
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NavigationBarController;
-import com.android.systemui.statusbar.car.hvac.HvacController;
-import com.android.systemui.statusbar.car.hvac.TemperatureView;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
@@ -52,18 +50,16 @@
 /** Navigation bars customized for the automotive use case. */
 public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks {
 
-    private final NavigationBarViewFactory mNavigationBarViewFactory;
+    private final CarNavigationBarController mCarNavigationBarController;
     private final WindowManager mWindowManager;
     private final DeviceProvisionedController mDeviceProvisionedController;
+    private final CommandQueue mCommandQueue;
     private final Lazy<FacetButtonTaskStackListener> mFacetButtonTaskStackListener;
     private final Handler mMainHandler;
     private final Lazy<KeyguardStateController> mKeyguardStateController;
-    private final Lazy<CarFacetButtonController> mFacetButtonController;
     private final Lazy<NavigationBarController> mNavigationBarController;
-    private final Lazy<HvacController> mHvacController;
 
     private IStatusBarService mBarService;
-    private CommandQueue mCommandQueue;
     private ActivityManagerWrapper mActivityManagerWrapper;
 
     // If the nav bar should be hidden when the soft keyboard is visible.
@@ -82,33 +78,25 @@
     // it's open.
     private boolean mDeviceIsSetUpForUser = true;
 
-    // Configuration values for if nav bars should be shown.
-    private boolean mShowBottom;
-    private boolean mShowLeft;
-    private boolean mShowRight;
-
-
     @Inject
     public CarNavigationBar(Context context,
-            NavigationBarViewFactory navigationBarViewFactory,
+            CarNavigationBarController carNavigationBarController,
             WindowManager windowManager,
             DeviceProvisionedController deviceProvisionedController,
+            CommandQueue commandQueue,
             Lazy<FacetButtonTaskStackListener> facetButtonTaskStackListener,
             @MainHandler Handler mainHandler,
             Lazy<KeyguardStateController> keyguardStateController,
-            Lazy<CarFacetButtonController> facetButtonController,
-            Lazy<NavigationBarController> navigationBarController,
-            Lazy<HvacController> hvacController) {
+            Lazy<NavigationBarController> navigationBarController) {
         super(context);
-        mNavigationBarViewFactory = navigationBarViewFactory;
+        mCarNavigationBarController = carNavigationBarController;
         mWindowManager = windowManager;
         mDeviceProvisionedController = deviceProvisionedController;
+        mCommandQueue = commandQueue;
         mFacetButtonTaskStackListener = facetButtonTaskStackListener;
         mMainHandler = mainHandler;
         mKeyguardStateController = keyguardStateController;
-        mFacetButtonController = facetButtonController;
         mNavigationBarController = navigationBarController;
-        mHvacController = hvacController;
     }
 
     @Override
@@ -118,17 +106,11 @@
                 com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard);
         mBottomNavBarVisible = false;
 
-        // Read configuration.
-        mShowBottom = mContext.getResources().getBoolean(R.bool.config_enableBottomNavigationBar);
-        mShowLeft = mContext.getResources().getBoolean(R.bool.config_enableLeftNavigationBar);
-        mShowRight = mContext.getResources().getBoolean(R.bool.config_enableRightNavigationBar);
-
         // Get bar service.
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
 
         // Connect into the status bar manager service
-        mCommandQueue = getComponent(CommandQueue.class);
         mCommandQueue.addCallback(this);
 
         RegisterStatusBarResult result = null;
@@ -157,7 +139,7 @@
         mActivityManagerWrapper = ActivityManagerWrapper.getInstance();
         mActivityManagerWrapper.registerTaskStackListener(mFacetButtonTaskStackListener.get());
 
-        mHvacController.get().connectToCarService();
+        mCarNavigationBarController.connectToHvac();
     }
 
     private void restartNavBarsIfNecessary() {
@@ -175,8 +157,7 @@
     private void restartNavBars() {
         // remove and reattach all hvac components such that we don't keep a reference to unused
         // ui elements
-        mHvacController.get().removeAllComponents();
-        mFacetButtonController.get().removeAll();
+        mCarNavigationBarController.removeAllFromHvac();
 
         if (mNavigationBarWindow != null) {
             mNavigationBarWindow.removeAllViews();
@@ -199,10 +180,6 @@
         if (mKeyguardStateController.get().isShowing()) {
             updateNavBarForKeyguardContent();
         }
-
-        // CarFacetButtonController was reset therefore we need to re-add the status bar elements
-        // to the controller.
-        // TODO(hseog): Add facet buttons in status bar to controller.
     }
 
     private void createNavigationBar(RegisterStatusBarResult result) {
@@ -224,54 +201,30 @@
     }
 
     private void buildNavBarWindows() {
-        if (mShowBottom) {
-            mNavigationBarWindow = mNavigationBarViewFactory.getBottomWindow();
-        }
-
-        if (mShowLeft) {
-            mLeftNavigationBarWindow = mNavigationBarViewFactory.getLeftWindow();
-        }
-
-        if (mShowRight) {
-            mRightNavigationBarWindow = mNavigationBarViewFactory.getRightWindow();
-        }
+        mNavigationBarWindow = mCarNavigationBarController.getBottomWindow();
+        mLeftNavigationBarWindow = mCarNavigationBarController.getLeftWindow();
+        mRightNavigationBarWindow = mCarNavigationBarController.getRightWindow();
     }
 
     private void buildNavBarContent() {
-        if (mShowBottom) {
-            mNavigationBarView = mNavigationBarViewFactory.getBottomBar(mDeviceIsSetUpForUser);
+        mNavigationBarView = mCarNavigationBarController.getBottomBar(mDeviceIsSetUpForUser);
+        if (mNavigationBarView != null) {
             mNavigationBarWindow.addView(mNavigationBarView);
-            addTemperatureViewToController(mNavigationBarView);
         }
 
-        if (mShowLeft) {
-            mLeftNavigationBarView = mNavigationBarViewFactory.getLeftBar(mDeviceIsSetUpForUser);
+        mLeftNavigationBarView = mCarNavigationBarController.getLeftBar(mDeviceIsSetUpForUser);
+        if (mLeftNavigationBarView != null) {
             mLeftNavigationBarWindow.addView(mLeftNavigationBarView);
-            addTemperatureViewToController(mLeftNavigationBarView);
         }
 
-        if (mShowRight) {
-            mRightNavigationBarView = mNavigationBarViewFactory.getRightBar(mDeviceIsSetUpForUser);
+        mRightNavigationBarView = mCarNavigationBarController.getRightBar(mDeviceIsSetUpForUser);
+        if (mRightNavigationBarView != null) {
             mRightNavigationBarWindow.addView(mRightNavigationBarView);
-            // Add ability to toggle notification center.
-            addTemperatureViewToController(mRightNavigationBarView);
-            // Add ability to close notification center on touch.
-        }
-    }
-
-    private void addTemperatureViewToController(View v) {
-        if (v instanceof TemperatureView) {
-            mHvacController.get().addHvacTextView((TemperatureView) v);
-        } else if (v instanceof ViewGroup) {
-            ViewGroup viewGroup = (ViewGroup) v;
-            for (int i = 0; i < viewGroup.getChildCount(); i++) {
-                addTemperatureViewToController(viewGroup.getChildAt(i));
-            }
         }
     }
 
     private void attachNavBarWindows() {
-        if (mShowBottom && !mBottomNavBarVisible) {
+        if (mNavigationBarWindow != null && !mBottomNavBarVisible) {
             mBottomNavBarVisible = true;
 
             WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
@@ -287,7 +240,7 @@
             mWindowManager.addView(mNavigationBarWindow, lp);
         }
 
-        if (mShowLeft) {
+        if (mLeftNavigationBarWindow != null) {
             int width = mContext.getResources().getDimensionPixelSize(
                     R.dimen.car_left_navigation_bar_width);
             WindowManager.LayoutParams leftlp = new WindowManager.LayoutParams(
@@ -304,7 +257,7 @@
             leftlp.gravity = Gravity.LEFT;
             mWindowManager.addView(mLeftNavigationBarWindow, leftlp);
         }
-        if (mShowRight) {
+        if (mRightNavigationBarWindow != null) {
             int width = mContext.getResources().getDimensionPixelSize(
                     R.dimen.car_right_navigation_bar_width);
             WindowManager.LayoutParams rightlp = new WindowManager.LayoutParams(
@@ -340,23 +293,8 @@
         }
 
         boolean isKeyboardVisible = (vis & InputMethodService.IME_VISIBLE) != 0;
-        showBottomNavBarWindow(isKeyboardVisible);
-    }
-
-    private void showBottomNavBarWindow(boolean isKeyboardVisible) {
-        if (!mShowBottom) {
-            return;
-        }
-
-        // If keyboard is visible and bottom nav bar not visible, this is the correct state, so do
-        // nothing. Same with if keyboard is not visible and bottom nav bar is visible.
-        if (isKeyboardVisible ^ mBottomNavBarVisible) {
-            return;
-        }
-
-        mNavigationBarViewFactory.getBottomWindow().setVisibility(
+        mCarNavigationBarController.setBottomWindowVisibility(
                 isKeyboardVisible ? View.GONE : View.VISIBLE);
-        mBottomNavBarVisible = !isKeyboardVisible;
     }
 
     private void updateNavBarForKeyguardContent() {
diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java
new file mode 100644
index 0000000..6bed69b
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java
@@ -0,0 +1,310 @@
+/*
+ * 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.navigationbar.car;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.car.hvac.HvacController;
+import com.android.systemui.statusbar.car.hvac.TemperatureView;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import dagger.Lazy;
+
+/** A single class which controls the navigation bar views. */
+@Singleton
+public class CarNavigationBarController {
+
+    private final Context mContext;
+    private final NavigationBarViewFactory mNavigationBarViewFactory;
+    private final Lazy<HvacController> mHvacControllerLazy;
+
+    private boolean mShowBottom;
+    private boolean mShowLeft;
+    private boolean mShowRight;
+
+    private View.OnTouchListener mTopBarTouchListener;
+    private View.OnTouchListener mBottomBarTouchListener;
+    private View.OnTouchListener mLeftBarTouchListener;
+    private View.OnTouchListener mRightBarTouchListener;
+    private NotificationsShadeController mNotificationsShadeController;
+
+    private CarNavigationBarView mTopView;
+    private CarNavigationBarView mBottomView;
+    private CarNavigationBarView mLeftView;
+    private CarNavigationBarView mRightView;
+
+    @Inject
+    public CarNavigationBarController(Context context,
+            NavigationBarViewFactory navigationBarViewFactory,
+            Lazy<HvacController> hvacControllerLazy) {
+        mContext = context;
+        mNavigationBarViewFactory = navigationBarViewFactory;
+        mHvacControllerLazy = hvacControllerLazy;
+
+        // Read configuration.
+        mShowBottom = mContext.getResources().getBoolean(R.bool.config_enableBottomNavigationBar);
+        mShowLeft = mContext.getResources().getBoolean(R.bool.config_enableLeftNavigationBar);
+        mShowRight = mContext.getResources().getBoolean(R.bool.config_enableRightNavigationBar);
+    }
+
+    /** Connect to hvac service. */
+    public void connectToHvac() {
+        mHvacControllerLazy.get().connectToCarService();
+    }
+
+    /** Clean up hvac. */
+    public void removeAllFromHvac() {
+        mHvacControllerLazy.get().removeAllComponents();
+    }
+
+    /** Gets the bottom window if configured to do so. */
+    @Nullable
+    public ViewGroup getBottomWindow() {
+        return mShowBottom ? mNavigationBarViewFactory.getBottomWindow() : null;
+    }
+
+    /** Gets the left window if configured to do so. */
+    @Nullable
+    public ViewGroup getLeftWindow() {
+        return mShowLeft ? mNavigationBarViewFactory.getLeftWindow() : null;
+    }
+
+    /** Gets the right window if configured to do so. */
+    @Nullable
+    public ViewGroup getRightWindow() {
+        return mShowRight ? mNavigationBarViewFactory.getRightWindow() : null;
+    }
+
+    /** Toggles the bottom nav bar visibility. */
+    public boolean setBottomWindowVisibility(@View.Visibility int visibility) {
+        return setWindowVisibility(getBottomWindow(), visibility);
+    }
+
+    /** Toggles the left nav bar visibility. */
+    public boolean setLeftWindowVisibility(@View.Visibility int visibility) {
+        return setWindowVisibility(getLeftWindow(), visibility);
+    }
+
+    /** Toggles the right nav bar visibility. */
+    public boolean setRightWindowVisibility(@View.Visibility int visibility) {
+        return setWindowVisibility(getRightWindow(), visibility);
+    }
+
+    private boolean setWindowVisibility(ViewGroup window, @View.Visibility int visibility) {
+        if (window == null) {
+            return false;
+        }
+
+        if (window.getVisibility() == visibility) {
+            return false;
+        }
+
+        window.setVisibility(visibility);
+        return true;
+    }
+
+    /** Gets the top navigation bar with the appropriate listeners set. */
+    @NonNull
+    public CarNavigationBarView getTopBar(boolean isSetUp) {
+        mTopView = mNavigationBarViewFactory.getTopBar(isSetUp);
+        mTopView.setStatusBarWindowTouchListener(mTopBarTouchListener);
+        mTopView.setNotificationsPanelController(mNotificationsShadeController);
+        addTemperatureViewToController(mTopView);
+        return mTopView;
+    }
+
+    /** Gets the bottom navigation bar with the appropriate listeners set. */
+    @Nullable
+    public CarNavigationBarView getBottomBar(boolean isSetUp) {
+        if (!mShowBottom) {
+            return null;
+        }
+
+        mBottomView = mNavigationBarViewFactory.getBottomBar(isSetUp);
+        mBottomView.setStatusBarWindowTouchListener(mBottomBarTouchListener);
+        mBottomView.setNotificationsPanelController(mNotificationsShadeController);
+        addTemperatureViewToController(mBottomView);
+        return mBottomView;
+    }
+
+    /** Gets the left navigation bar with the appropriate listeners set. */
+    @Nullable
+    public CarNavigationBarView getLeftBar(boolean isSetUp) {
+        if (!mShowLeft) {
+            return null;
+        }
+
+        mLeftView = mNavigationBarViewFactory.getLeftBar(isSetUp);
+        mLeftView.setStatusBarWindowTouchListener(mLeftBarTouchListener);
+        mLeftView.setNotificationsPanelController(mNotificationsShadeController);
+        addTemperatureViewToController(mLeftView);
+        return mLeftView;
+    }
+
+    /** Gets the right navigation bar with the appropriate listeners set. */
+    @Nullable
+    public CarNavigationBarView getRightBar(boolean isSetUp) {
+        if (!mShowRight) {
+            return null;
+        }
+
+        mRightView = mNavigationBarViewFactory.getRightBar(isSetUp);
+        mRightView.setStatusBarWindowTouchListener(mRightBarTouchListener);
+        mRightView.setNotificationsPanelController(mNotificationsShadeController);
+        addTemperatureViewToController(mRightView);
+        return mRightView;
+    }
+
+    /** Sets a touch listener for the top navigation bar. */
+    public void registerTopBarTouchListener(View.OnTouchListener listener) {
+        mTopBarTouchListener = listener;
+        if (mTopView != null) {
+            mTopView.setStatusBarWindowTouchListener(mTopBarTouchListener);
+        }
+    }
+
+    /** Sets a touch listener for the bottom navigation bar. */
+    public void registerBottomBarTouchListener(View.OnTouchListener listener) {
+        mBottomBarTouchListener = listener;
+        if (mBottomView != null) {
+            mBottomView.setStatusBarWindowTouchListener(mBottomBarTouchListener);
+        }
+    }
+
+    /** Sets a touch listener for the left navigation bar. */
+    public void registerLeftBarTouchListener(View.OnTouchListener listener) {
+        mLeftBarTouchListener = listener;
+        if (mLeftView != null) {
+            mLeftView.setStatusBarWindowTouchListener(mLeftBarTouchListener);
+        }
+    }
+
+    /** Sets a touch listener for the right navigation bar. */
+    public void registerRightBarTouchListener(View.OnTouchListener listener) {
+        mRightBarTouchListener = listener;
+        if (mRightView != null) {
+            mRightView.setStatusBarWindowTouchListener(mRightBarTouchListener);
+        }
+    }
+
+    /** Sets a notification controller which toggles the notification panel. */
+    public void registerNotificationController(
+            NotificationsShadeController notificationsShadeController) {
+        mNotificationsShadeController = notificationsShadeController;
+        if (mTopView != null) {
+            mTopView.setNotificationsPanelController(mNotificationsShadeController);
+        }
+        if (mBottomView != null) {
+            mBottomView.setNotificationsPanelController(mNotificationsShadeController);
+        }
+        if (mLeftView != null) {
+            mLeftView.setNotificationsPanelController(mNotificationsShadeController);
+        }
+        if (mRightView != null) {
+            mRightView.setNotificationsPanelController(mNotificationsShadeController);
+        }
+    }
+
+    /**
+     * Shows all of the keyguard specific buttons on the valid instances of
+     * {@link CarNavigationBarView}.
+     */
+    public void showAllKeyguardButtons(boolean isSetUp) {
+        checkAllBars(isSetUp);
+        if (mTopView != null) {
+            mTopView.showKeyguardButtons();
+        }
+        if (mBottomView != null) {
+            mBottomView.showKeyguardButtons();
+        }
+        if (mLeftView != null) {
+            mLeftView.showKeyguardButtons();
+        }
+        if (mRightView != null) {
+            mRightView.showKeyguardButtons();
+        }
+    }
+
+    /**
+     * Hides all of the keyguard specific buttons on the valid instances of
+     * {@link CarNavigationBarView}.
+     */
+    public void hideAllKeyguardButtons(boolean isSetUp) {
+        checkAllBars(isSetUp);
+        if (mTopView != null) {
+            mTopView.hideKeyguardButtons();
+        }
+        if (mBottomView != null) {
+            mBottomView.hideKeyguardButtons();
+        }
+        if (mLeftView != null) {
+            mLeftView.hideKeyguardButtons();
+        }
+        if (mRightView != null) {
+            mRightView.hideKeyguardButtons();
+        }
+    }
+
+    /** Toggles whether the notifications icon has an unseen indicator or not. */
+    public void toggleAllNotificationsUnseenIndicator(boolean isSetUp, boolean hasUnseen) {
+        checkAllBars(isSetUp);
+        if (mTopView != null) {
+            mTopView.toggleNotificationUnseenIndicator(hasUnseen);
+        }
+        if (mBottomView != null) {
+            mBottomView.toggleNotificationUnseenIndicator(hasUnseen);
+        }
+        if (mLeftView != null) {
+            mLeftView.toggleNotificationUnseenIndicator(hasUnseen);
+        }
+        if (mRightView != null) {
+            mRightView.toggleNotificationUnseenIndicator(hasUnseen);
+        }
+    }
+
+    /** Interface for controlling the notifications shade. */
+    public interface NotificationsShadeController {
+        /** Toggles the visibility of the notifications shade. */
+        void togglePanel();
+    }
+
+    private void addTemperatureViewToController(View v) {
+        if (v instanceof TemperatureView) {
+            mHvacControllerLazy.get().addHvacTextView((TemperatureView) v);
+        } else if (v instanceof ViewGroup) {
+            ViewGroup viewGroup = (ViewGroup) v;
+            for (int i = 0; i < viewGroup.getChildCount(); i++) {
+                addTemperatureViewToController(viewGroup.getChildAt(i));
+            }
+        }
+    }
+
+    private void checkAllBars(boolean isSetUp) {
+        mTopView = getTopBar(isSetUp);
+        mBottomView = getBottomBar(isSetUp);
+        mLeftView = getLeftBar(isSetUp);
+        mRightView = getRightBar(isSetUp);
+    }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarView.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarView.java
index afb6954..28da169 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarView.java
@@ -24,7 +24,8 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.car.CarStatusBar;
+import com.android.systemui.navigationbar.car.CarNavigationBarController.NotificationsShadeController;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 
 /**
@@ -36,7 +37,7 @@
 public class CarNavigationBarView extends LinearLayout {
     private View mNavButtons;
     private CarNavigationButton mNotificationsButton;
-    private CarStatusBar mCarStatusBar;
+    private NotificationsShadeController mNotificationsShadeController;
     private Context mContext;
     private View mLockScreenButtons;
     // used to wire in open/close gestures for notifications
@@ -63,7 +64,8 @@
             // container is in the view.
             StatusBarIconController.DarkIconManager mDarkIconManager =
                     new StatusBarIconController.DarkIconManager(
-                            mStatusIcons.findViewById(R.id.statusIcons));
+                            mStatusIcons.findViewById(R.id.statusIcons),
+                            Dependency.get(CommandQueue.class));
             mDarkIconManager.setShouldLog(true);
             Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
         }
@@ -82,12 +84,18 @@
         return super.onInterceptTouchEvent(ev);
     }
 
-    public void setStatusBar(CarStatusBar carStatusBar) {
-        mCarStatusBar = carStatusBar;
+    /** Sets the notifications panel controller. */
+    public void setNotificationsPanelController(NotificationsShadeController controller) {
+        mNotificationsShadeController = controller;
+    }
+
+    /** Gets the notifications panel controller. */
+    public NotificationsShadeController getNotificationsPanelController() {
+        return mNotificationsShadeController;
     }
 
     /**
-     * Set a touch listener that will be called from onInterceptTouchEvent and onTouchEvent
+     * Sets a touch listener that will be called from onInterceptTouchEvent and onTouchEvent
      *
      * @param statusBarWindowTouchListener The listener to call from touch and intercept touch
      */
@@ -95,6 +103,11 @@
         mStatusBarWindowTouchListener = statusBarWindowTouchListener;
     }
 
+    /** Gets the touch listener that will be called from onInterceptTouchEvent and onTouchEvent. */
+    public OnTouchListener getStatusBarWindowTouchListener() {
+        return mStatusBarWindowTouchListener;
+    }
+
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         if (mStatusBarWindowTouchListener != null) {
@@ -104,7 +117,9 @@
     }
 
     protected void onNotificationsClick(View v) {
-        mCarStatusBar.togglePanel();
+        if (mNotificationsShadeController != null) {
+            mNotificationsShadeController.togglePanel();
+        }
     }
 
     /**
diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationButton.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationButton.java
index 707d80f..922bfff 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationButton.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationButton.java
@@ -85,6 +85,7 @@
         super.onFinishInflate();
         setScaleType(ImageView.ScaleType.CENTER);
         setAlpha(mUnselectedAlpha);
+        setImageResource(mIconResourceId);
         try {
             if (mIntent != null) {
                 final Intent intent = Intent.parseUri(mIntent, Intent.URI_INTENT_SCHEME);
@@ -149,6 +150,11 @@
         updateImage();
     }
 
+    /** Gets whether the icon is in an unseen state. */
+    public boolean getUnseen() {
+        return mHasUnseen;
+    }
+
     private void updateImage() {
         if (mHasUnseen) {
             setImageResource(mSelected ? UNSEEN_SELECTED_ICON_RESOURCE_ID
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 cd81a5c..110b32b 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -27,11 +27,11 @@
 import android.car.drivingstate.CarDrivingStateEvent;
 import android.car.drivingstate.CarUxRestrictionsManager;
 import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
-import android.car.trust.CarTrustAgentEnrollmentManager;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.PowerManager;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.GestureDetector;
@@ -75,11 +75,13 @@
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.navigationbar.car.CarFacetButtonController;
+import com.android.systemui.navigationbar.car.CarNavigationBarController;
 import com.android.systemui.navigationbar.car.CarNavigationBarView;
-import com.android.systemui.navigationbar.car.NavigationBarViewFactory;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.qs.car.CarQSFragment;
+import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 import com.android.systemui.statusbar.NavigationBarController;
@@ -92,8 +94,6 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.car.hvac.HvacController;
-import com.android.systemui.statusbar.car.hvac.TemperatureView;
 import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NewNotifPipeline;
@@ -106,8 +106,11 @@
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.phone.AutoHideController;
+import com.android.systemui.statusbar.phone.BiometricUnlockController;
 import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
 import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.phone.DozeScrimController;
+import com.android.systemui.statusbar.phone.DozeServiceHost;
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.LightBarController;
@@ -125,6 +128,7 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
+import com.android.systemui.statusbar.policy.RemoteInputUriController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.util.InjectionInflationController;
@@ -133,7 +137,6 @@
 import java.io.PrintWriter;
 import java.util.Map;
 
-import javax.inject.Inject;
 import javax.inject.Named;
 
 import dagger.Lazy;
@@ -154,6 +157,9 @@
     private float mOpeningVelocity = DEFAULT_FLING_VELOCITY;
     private float mClosingVelocity = DEFAULT_FLING_VELOCITY;
 
+    private float mBackgroundAlphaDiff;
+    private float mInitialBackgroundAlpha;
+
     private FullscreenUserSwitcher mFullscreenUserSwitcher;
 
     private CarBatteryController mCarBatteryController;
@@ -161,23 +167,13 @@
     private Drawable mNotificationPanelBackground;
 
     private ViewGroup mTopNavigationBarContainer;
-    private ViewGroup mNavigationBarWindow;
-    private ViewGroup mLeftNavigationBarWindow;
-    private ViewGroup mRightNavigationBarWindow;
     private CarNavigationBarView mTopNavigationBarView;
-    private CarNavigationBarView mNavigationBarView;
-    private CarNavigationBarView mLeftNavigationBarView;
-    private CarNavigationBarView mRightNavigationBarView;
 
     private final Object mQueueLock = new Object();
-    private boolean mShowLeft;
-    private boolean mShowRight;
-    private boolean mShowBottom;
-    private final NavigationBarViewFactory mNavigationBarViewFactory;
+    private final CarNavigationBarController mCarNavigationBarController;
     private CarFacetButtonController mCarFacetButtonController;
     private DeviceProvisionedController mDeviceProvisionedController;
     private boolean mDeviceIsSetUpForUser = true;
-    private HvacController mHvacController;
     private DrivingStateHelper mDrivingStateHelper;
     private PowerManagerHelper mPowerManagerHelper;
     private FlingAnimationUtils mFlingAnimationUtils;
@@ -224,6 +220,8 @@
     // Whether heads-up notifications should be shown when shade is open.
     private boolean mEnableHeadsUpNotificationWhenNotificationShadeOpen;
 
+    private CarUxRestrictionManagerWrapper mCarUxRestrictionManagerWrapper;
+
     private final CarPowerStateListener mCarPowerStateListener =
             (int state) -> {
                 // When the car powers on, clear all notifications and mute/unread states.
@@ -238,7 +236,6 @@
                 }
             };
 
-    @Inject
     public CarStatusBar(
             Context context,
             FeatureFlags featureFlags,
@@ -299,9 +296,15 @@
             DozeParameters dozeParameters,
             ScrimController scrimController,
             Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
-
+            Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
+            DozeServiceHost dozeServiceHost,
+            PowerManager powerManager,
+            DozeScrimController dozeScrimController,
+            CommandQueue commandQueue,
+            PluginManager pluginManager,
+            RemoteInputUriController remoteInputUriController,
             /* Car Settings injected components. */
-            NavigationBarViewFactory navigationBarViewFactory) {
+            CarNavigationBarController carNavigationBarController) {
         super(
                 context,
                 featureFlags,
@@ -361,9 +364,17 @@
                 notifLog,
                 dozeParameters,
                 scrimController,
-                lockscreenWallpaperLazy);
+                null /* keyguardLiftController */,
+                lockscreenWallpaperLazy,
+                biometricUnlockControllerLazy,
+                dozeServiceHost,
+                powerManager,
+                dozeScrimController,
+                commandQueue,
+                pluginManager,
+                remoteInputUriController);
         mScrimController = scrimController;
-        mNavigationBarViewFactory = navigationBarViewFactory;
+        mCarNavigationBarController = carNavigationBarController;
     }
 
     @Override
@@ -378,9 +389,24 @@
         mScreenLifecycle = Dependency.get(ScreenLifecycle.class);
         mScreenLifecycle.addObserver(mScreenObserver);
 
-        // Need to initialize HVAC controller before calling super.start - before system bars are
-        // created.
-        mHvacController = new HvacController(mContext);
+      	// Notification bar related setup.
+        mInitialBackgroundAlpha = (float) mContext.getResources().getInteger(
+            R.integer.config_initialNotificationBackgroundAlpha) / 100;
+        if (mInitialBackgroundAlpha < 0 || mInitialBackgroundAlpha > 100) {
+            throw new RuntimeException(
+              "Unable to setup notification bar due to incorrect initial background alpha"
+                      + " percentage");
+        }
+        float finalBackgroundAlpha = Math.max(
+            mInitialBackgroundAlpha,
+            (float) mContext.getResources().getInteger(
+                R.integer.config_finalNotificationBackgroundAlpha) / 100);
+        if (finalBackgroundAlpha < 0 || finalBackgroundAlpha > 100) {
+            throw new RuntimeException(
+              "Unable to setup notification bar due to incorrect final background alpha"
+                      + " percentage");
+        }
+        mBackgroundAlphaDiff = finalBackgroundAlpha - mInitialBackgroundAlpha;
 
         super.start();
 
@@ -395,36 +421,36 @@
         createBatteryController();
         mCarBatteryController.startListening();
 
-        mHvacController.connectToCarService();
-
         mDeviceProvisionedController.addCallback(
                 new DeviceProvisionedController.DeviceProvisionedListener() {
                     @Override
                     public void onUserSetupChanged() {
-                        mHandler.post(() -> restartNavBarsIfNecessary());
+                        mHandler.post(() -> resetSystemBarsIfNecessary());
                     }
 
                     @Override
                     public void onUserSwitched() {
-                        mHandler.post(() -> restartNavBarsIfNecessary());
+                        mHandler.post(() -> resetSystemBarsIfNecessary());
                     }
                 });
 
+        // Used by onDrivingStateChanged and it can be called inside
+        // DrivingStateHelper.connectToCarService()
+        mSwitchToGuestTimer = new SwitchToGuestTimer(mContext);
+
         // Register a listener for driving state changes.
         mDrivingStateHelper = new DrivingStateHelper(mContext, this::onDrivingStateChanged);
         mDrivingStateHelper.connectToCarService();
 
         mPowerManagerHelper = new PowerManagerHelper(mContext, mCarPowerStateListener);
         mPowerManagerHelper.connectToCarService();
-
-        mSwitchToGuestTimer = new SwitchToGuestTimer(mContext);
     }
 
-    private void restartNavBarsIfNecessary() {
+    private void resetSystemBarsIfNecessary() {
         boolean currentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
         if (mDeviceIsSetUpForUser != currentUserSetup) {
             mDeviceIsSetUpForUser = currentUserSetup;
-            restartNavBars();
+            resetSystemBars();
         }
     }
 
@@ -432,89 +458,36 @@
      * Remove all content from navbars and rebuild them. Used to allow for different nav bars
      * before and after the device is provisioned. . Also for change of density and font size.
      */
-    private void restartNavBars() {
-        // remove and reattach all hvac components such that we don't keep a reference to unused
-        // ui elements
-        mHvacController.removeAllComponents();
+    private void resetSystemBars() {
         mCarFacetButtonController.removeAll();
 
-        if (mNavigationBarWindow != null) {
-            mNavigationBarView = null;
-        }
-        if (mLeftNavigationBarWindow != null) {
-            mLeftNavigationBarView = null;
-        }
-        if (mRightNavigationBarWindow != null) {
-            mRightNavigationBarView = null;
-        }
-
         buildNavBarContent();
         // CarFacetButtonController was reset therefore we need to re-add the status bar elements
         // to the controller.
         mCarFacetButtonController.addAllFacetButtons(mStatusBarWindow);
     }
 
-    private void addTemperatureViewToController(View v) {
-        if (v instanceof TemperatureView) {
-            mHvacController.addHvacTextView((TemperatureView) v);
-        } else if (v instanceof ViewGroup) {
-            ViewGroup viewGroup = (ViewGroup) v;
-            for (int i = 0; i < viewGroup.getChildCount(); i++) {
-                addTemperatureViewToController(viewGroup.getChildAt(i));
-            }
-        }
-    }
-
     /**
      * 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) {
-        if (mNavigationBarWindow != null) {
-            mNavigationBarWindow.setVisibility(visibility);
-        }
-        if (mLeftNavigationBarWindow != null) {
-            mLeftNavigationBarWindow.setVisibility(visibility);
-        }
-        if (mRightNavigationBarWindow != null) {
-            mRightNavigationBarWindow.setVisibility(visibility);
-        }
+        mCarNavigationBarController.setBottomWindowVisibility(visibility);
+        mCarNavigationBarController.setLeftWindowVisibility(visibility);
+        mCarNavigationBarController.setRightWindowVisibility(visibility);
     }
 
     @Override
     public boolean hideKeyguard() {
         boolean result = super.hideKeyguard();
-        if (mNavigationBarView != null) {
-            mNavigationBarView.hideKeyguardButtons();
-        }
-        if (mLeftNavigationBarView != null) {
-            mLeftNavigationBarView.hideKeyguardButtons();
-        }
-        if (mRightNavigationBarView != null) {
-            mRightNavigationBarView.hideKeyguardButtons();
-        }
+        mCarNavigationBarController.hideAllKeyguardButtons(mDeviceIsSetUpForUser);
         return result;
     }
 
     @Override
     public void showKeyguard() {
         super.showKeyguard();
-        updateNavBarForKeyguardContent();
-    }
-
-    /**
-     * Switch to the keyguard applicable content contained in the nav bars
-     */
-    private void updateNavBarForKeyguardContent() {
-        if (mNavigationBarView != null) {
-            mNavigationBarView.showKeyguardButtons();
-        }
-        if (mLeftNavigationBarView != null) {
-            mLeftNavigationBarView.showKeyguardButtons();
-        }
-        if (mRightNavigationBarView != null) {
-            mRightNavigationBarView.showKeyguardButtons();
-        }
+        mCarNavigationBarController.showAllKeyguardButtons(mDeviceIsSetUpForUser);
     }
 
     @Override
@@ -607,31 +580,31 @@
                 animateCollapsePanels();
             }
         });
-        Car car = Car.createCar(mContext);
-        CarUxRestrictionsManager carUxRestrictionsManager = (CarUxRestrictionsManager)
-                car.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);
         CarNotificationListener carNotificationListener = new CarNotificationListener();
-        CarUxRestrictionManagerWrapper carUxRestrictionManagerWrapper =
-                new CarUxRestrictionManagerWrapper();
-        carUxRestrictionManagerWrapper.setCarUxRestrictionsManager(carUxRestrictionsManager);
+        mCarUxRestrictionManagerWrapper = new CarUxRestrictionManagerWrapper();
+        // This can take time if car service is not ready up to this time.
+        // TODO(b/142808072) Refactor CarUxRestrictionManagerWrapper to allow setting
+        // CarUxRestrictionsManager later and switch to Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT.
+        Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER,
+                (car, ready) -> {
+                    if (!ready) {
+                        return;
+                    }
+                    CarUxRestrictionsManager carUxRestrictionsManager =
+                            (CarUxRestrictionsManager)
+                                    car.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);
+                    mCarUxRestrictionManagerWrapper.setCarUxRestrictionsManager(
+                            carUxRestrictionsManager);
+                });
 
         mNotificationDataManager = new NotificationDataManager();
         mNotificationDataManager.setOnUnseenCountUpdateListener(
                 () -> {
-                    if (mNavigationBarView != null && mNotificationDataManager != null) {
-                        Boolean hasUnseen =
+                    if (mNotificationDataManager != null) {
+                        boolean hasUnseen =
                                 mNotificationDataManager.getUnseenNotificationCount() > 0;
-                        if (mNavigationBarView != null) {
-                            mNavigationBarView.toggleNotificationUnseenIndicator(hasUnseen);
-                        }
-
-                        if (mLeftNavigationBarView != null) {
-                            mLeftNavigationBarView.toggleNotificationUnseenIndicator(hasUnseen);
-                        }
-
-                        if (mRightNavigationBarView != null) {
-                            mRightNavigationBarView.toggleNotificationUnseenIndicator(hasUnseen);
-                        }
+                        mCarNavigationBarController.toggleAllNotificationsUnseenIndicator(
+                                mDeviceIsSetUpForUser, hasUnseen);
                     }
                 });
 
@@ -642,7 +615,7 @@
                         mNotificationClickHandlerFactory, mNotificationDataManager);
         mNotificationClickHandlerFactory.setNotificationDataManager(mNotificationDataManager);
 
-        carNotificationListener.registerAsSystemService(mContext, carUxRestrictionManagerWrapper,
+        carNotificationListener.registerAsSystemService(mContext, mCarUxRestrictionManagerWrapper,
                 carHeadsUpNotificationManager, mNotificationDataManager);
 
         mNotificationView = mStatusBarWindow.findViewById(R.id.notification_view);
@@ -742,7 +715,7 @@
                 mNotificationView,
                 PreprocessingManager.getInstance(mContext),
                 carNotificationListener,
-                carUxRestrictionManagerWrapper,
+                mCarUxRestrictionManagerWrapper,
                 mNotificationDataManager);
         mNotificationViewController.enable();
     }
@@ -885,61 +858,33 @@
 
     @Override
     protected void createNavigationBar(@Nullable RegisterStatusBarResult result) {
-        mShowBottom = mContext.getResources().getBoolean(R.bool.config_enableBottomNavigationBar);
-        mShowLeft = mContext.getResources().getBoolean(R.bool.config_enableLeftNavigationBar);
-        mShowRight = mContext.getResources().getBoolean(R.bool.config_enableRightNavigationBar);
+        mTopNavigationBarContainer = mStatusBarWindow
+                .findViewById(R.id.car_top_navigation_bar_container);
 
-        buildNavBarWindows();
         buildNavBarContent();
     }
 
     private void buildNavBarContent() {
         buildTopBar();
 
-        if (mShowBottom) {
-            mNavigationBarView = mNavigationBarViewFactory.getBottomBar(mDeviceIsSetUpForUser);
-            mNavigationBarView.setStatusBar(this);
-            mNavigationBarView.setStatusBarWindowTouchListener(mNavBarNotificationTouchListener);
-        }
+        mCarNavigationBarController.registerBottomBarTouchListener(
+                mNavBarNotificationTouchListener);
 
-        if (mShowLeft) {
-            mLeftNavigationBarView = mNavigationBarViewFactory.getLeftBar(mDeviceIsSetUpForUser);
-            mLeftNavigationBarView.setStatusBar(this);
-            mLeftNavigationBarView.setStatusBarWindowTouchListener(
-                    mNavBarNotificationTouchListener);
-        }
+        mCarNavigationBarController.registerLeftBarTouchListener(
+                mNavBarNotificationTouchListener);
 
-        if (mShowRight) {
-            mRightNavigationBarView = mNavigationBarViewFactory.getLeftBar(mDeviceIsSetUpForUser);
-            mRightNavigationBarView.setStatusBar(this);
-            mRightNavigationBarView.setStatusBarWindowTouchListener(
-                    mNavBarNotificationTouchListener);
-        }
-    }
+        mCarNavigationBarController.registerRightBarTouchListener(
+                mNavBarNotificationTouchListener);
 
-    private void buildNavBarWindows() {
-        mTopNavigationBarContainer = mStatusBarWindow
-                .findViewById(R.id.car_top_navigation_bar_container);
-
-        if (mShowBottom) {
-            mNavigationBarWindow = mNavigationBarViewFactory.getBottomWindow();
-        }
-        if (mShowLeft) {
-            mLeftNavigationBarWindow = mNavigationBarViewFactory.getLeftWindow();
-        }
-        if (mShowRight) {
-            mRightNavigationBarWindow = mNavigationBarViewFactory.getRightWindow();
-        }
+        mCarNavigationBarController.registerNotificationController(() -> togglePanel());
     }
 
     private void buildTopBar() {
         mTopNavigationBarContainer.removeAllViews();
-        mTopNavigationBarView = mNavigationBarViewFactory.getTopBar(mDeviceIsSetUpForUser);
+        mTopNavigationBarView = mCarNavigationBarController.getTopBar(mDeviceIsSetUpForUser);
+        mCarNavigationBarController.registerTopBarTouchListener(
+                mTopNavBarNotificationTouchListener);
         mTopNavigationBarContainer.addView(mTopNavigationBarView);
-
-        mTopNavigationBarView.setStatusBar(this);
-        addTemperatureViewToController(mTopNavigationBarView);
-        mTopNavigationBarView.setStatusBarWindowTouchListener(mTopNavBarNotificationTouchListener);
     }
 
     @Override
@@ -1019,12 +964,8 @@
         UserSwitcherController userSwitcherController =
                 Dependency.get(UserSwitcherController.class);
         if (userSwitcherController.useFullscreenUserSwitcher()) {
-            Car car = Car.createCar(mContext);
-            CarTrustAgentEnrollmentManager enrollmentManager = (CarTrustAgentEnrollmentManager) car
-                    .getCarManager(Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE);
             mFullscreenUserSwitcher = new FullscreenUserSwitcher(this,
-                    mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub),
-                    enrollmentManager, mContext);
+                    mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub), mContext);
         } else {
             super.createUserSwitcher();
         }
@@ -1107,7 +1048,7 @@
     @Override
     public void onDensityOrFontScaleChanged() {
         super.onDensityOrFontScaleChanged();
-        restartNavBars();
+        resetSystemBars();
         // Need to update the background on density changed in case the change was due to night
         // mode.
         mNotificationPanelBackground = getDefaultWallpaper();
@@ -1135,17 +1076,22 @@
             mHandleBar.setTranslationY(height - mHandleBar.getHeight() - lp.bottomMargin);
         }
         if (mNotificationView.getHeight() > 0) {
-            // Calculates the alpha value for the background based on how much of the notification
-            // shade is visible to the user. When the notification shade is completely open then
-            // alpha value will be 1.
-            float alpha = (float) height / mNotificationView.getHeight();
             Drawable background = mNotificationView.getBackground().mutate();
-
-            background.setAlpha((int) (alpha * 255));
+            background.setAlpha((int) (getBackgroundAlpha(height) * 255));
             mNotificationView.setBackground(background);
         }
     }
 
+    /**
+     * Calculates the alpha value for the background based on how much of the notification
+     * shade is visible to the user. When the notification shade is completely open then
+     * alpha value will be 1.
+     */
+    private float getBackgroundAlpha(int height) {
+        return mInitialBackgroundAlpha +
+            ((float) height / mNotificationView.getHeight() * mBackgroundAlphaDiff);
+    }
+
     @Override
     public void onConfigChanged(Configuration newConfig) {
         super.onConfigChanged(newConfig);
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java
index a442426..cd87e78 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/DrivingStateHelper.java
@@ -17,14 +17,11 @@
 package com.android.systemui.statusbar.car;
 
 import android.car.Car;
-import android.car.CarNotConnectedException;
+import android.car.Car.CarServiceLifecycleListener;
 import android.car.drivingstate.CarDrivingStateEvent;
 import android.car.drivingstate.CarDrivingStateManager;
 import android.car.drivingstate.CarDrivingStateManager.CarDrivingStateEventListener;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.ServiceConnection;
-import android.os.IBinder;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
@@ -55,16 +52,11 @@
         if (mDrivingStateManager == null) {
             return false;
         }
-        try {
-            CarDrivingStateEvent currentState = mDrivingStateManager.getCurrentCarDrivingState();
-            if (currentState != null) {
-                return currentState.eventValue == CarDrivingStateEvent.DRIVING_STATE_IDLING
-                        || currentState.eventValue == CarDrivingStateEvent.DRIVING_STATE_MOVING;
-            }
-        } catch (CarNotConnectedException e) {
-            Log.e(TAG, "Cannot determine current driving state. Car not connected", e);
+        CarDrivingStateEvent currentState = mDrivingStateManager.getCurrentCarDrivingState();
+        if (currentState != null) {
+            return currentState.eventValue == CarDrivingStateEvent.DRIVING_STATE_IDLING
+                    || currentState.eventValue == CarDrivingStateEvent.DRIVING_STATE_MOVING;
         }
-
         return false; // Default to false.
     }
 
@@ -72,55 +64,25 @@
      * Establishes connection with the Car service.
      */
     public void connectToCarService() {
-        mCar = Car.createCar(mContext, mCarConnectionListener);
-        if (mCar != null) {
-            mCar.connect();
-        }
+        mCar = Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
+                mCarServiceLifecycleListener);
     }
 
-    /**
-     * Disconnects from Car service and cleans up listeners.
-     */
-    public void disconnectFromCarService() {
-        if (mCar != null) {
-            mCar.disconnect();
+    private final CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> {
+        if (!ready) {
+            return;
         }
-    }
-
-    private final ServiceConnection mCarConnectionListener =
-            new ServiceConnection() {
-                public void onServiceConnected(ComponentName name, IBinder service) {
-                    logD("Car Service connected");
-                    try {
-                        mDrivingStateManager = (CarDrivingStateManager) mCar.getCarManager(
-                                Car.CAR_DRIVING_STATE_SERVICE);
-                        if (mDrivingStateManager != null) {
-                            mDrivingStateManager.registerListener(mDrivingStateHandler);
-                            mDrivingStateHandler.onDrivingStateChanged(
-                                    mDrivingStateManager.getCurrentCarDrivingState());
-                        } else {
-                            Log.e(TAG, "CarDrivingStateService service not available");
-                        }
-                    } catch (CarNotConnectedException e) {
-                        Log.e(TAG, "Car not connected", e);
-                    }
-                }
-
-                @Override
-                public void onServiceDisconnected(ComponentName name) {
-                    destroyDrivingStateManager();
-                }
-            };
-
-    private void destroyDrivingStateManager() {
-        try {
-            if (mDrivingStateManager != null) {
-                mDrivingStateManager.unregisterListener();
-            }
-        } catch (CarNotConnectedException e) {
-            Log.e(TAG, "Error unregistering listeners", e);
+        logD("Car Service connected");
+        mDrivingStateManager = (CarDrivingStateManager) car.getCarManager(
+                Car.CAR_DRIVING_STATE_SERVICE);
+        if (mDrivingStateManager != null) {
+            mDrivingStateManager.registerListener(mDrivingStateHandler);
+            mDrivingStateHandler.onDrivingStateChanged(
+                    mDrivingStateManager.getCurrentCarDrivingState());
+        } else {
+            Log.e(TAG, "CarDrivingStateService service not available");
         }
-    }
+    };
 
     private void logD(String message) {
         if (Log.isLoggable(TAG, Log.DEBUG)) {
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 0f7c1ee..31aced0 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -18,6 +18,7 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.car.Car;
 import android.car.trust.CarTrustAgentEnrollmentManager;
 import android.car.userlib.CarUserManagerHelper;
 import android.content.BroadcastReceiver;
@@ -50,7 +51,7 @@
     private final CarStatusBar mStatusBar;
     private final Context mContext;
     private final UserManager mUserManager;
-    private final CarTrustAgentEnrollmentManager mEnrollmentManager;
+    private CarTrustAgentEnrollmentManager mEnrollmentManager;
     private CarTrustAgentUnlockDialogHelper mUnlockDialogHelper;
     private UserGridRecyclerView.UserRecord mSelectedUser;
     private CarUserManagerHelper mCarUserManagerHelper;
@@ -64,13 +65,11 @@
             mContext.unregisterReceiver(mUserUnlockReceiver);
         }
     };
+    private final Car mCar;
 
-
-    public FullscreenUserSwitcher(CarStatusBar statusBar, ViewStub containerStub,
-            CarTrustAgentEnrollmentManager enrollmentManager, Context context) {
+    public FullscreenUserSwitcher(CarStatusBar statusBar, ViewStub containerStub, Context context) {
         mStatusBar = statusBar;
         mParent = containerStub.inflate();
-        mEnrollmentManager = enrollmentManager;
         mContext = context;
 
         View container = mParent.findViewById(R.id.container);
@@ -86,6 +85,15 @@
         mUnlockDialogHelper = new CarTrustAgentUnlockDialogHelper(mContext);
         mUserManager = mContext.getSystemService(UserManager.class);
 
+        mCar = Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
+                (car, ready) -> {
+                    if (!ready) {
+                        return;
+                    }
+                    mEnrollmentManager = (CarTrustAgentEnrollmentManager) car
+                            .getCarManager(Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE);
+                });
+
         mShortAnimDuration = container.getResources()
                 .getInteger(android.R.integer.config_shortAnimTime);
         IntentFilter filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
@@ -201,6 +209,9 @@
     }
 
     private boolean hasTrustedDevice(int uid) {
+        if (mEnrollmentManager == null) { // car service not ready, so it cannot be available.
+            return false;
+        }
         return !mEnrollmentManager.getEnrolledDeviceInfoForUser(uid).isEmpty();
     }
 
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/PowerManagerHelper.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/PowerManagerHelper.java
index 8de1439..a27dd34 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/PowerManagerHelper.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/PowerManagerHelper.java
@@ -18,13 +18,10 @@
 
 import android.annotation.NonNull;
 import android.car.Car;
-import android.car.CarNotConnectedException;
+import android.car.Car.CarServiceLifecycleListener;
 import android.car.hardware.power.CarPowerManager;
 import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.ServiceConnection;
-import android.os.IBinder;
 import android.util.Log;
 
 /**
@@ -39,55 +36,30 @@
     private Car mCar;
     private CarPowerManager mCarPowerManager;
 
-    private final ServiceConnection mCarConnectionListener =
-            new ServiceConnection() {
-                public void onServiceConnected(ComponentName name, IBinder service) {
-                    Log.d(TAG, "Car Service connected");
-                    try {
-                        mCarPowerManager = (CarPowerManager) mCar.getCarManager(Car.POWER_SERVICE);
-                        if (mCarPowerManager != null) {
-                            mCarPowerManager.setListener(mCarPowerStateListener);
-                        } else {
-                            Log.e(TAG, "CarPowerManager service not available");
-                        }
-                    } catch (CarNotConnectedException e) {
-                        Log.e(TAG, "Car not connected", e);
-                    }
-                }
-
-                @Override
-                public void onServiceDisconnected(ComponentName name) {
-                    destroyCarPowerManager();
-                }
-            };
+    private final CarServiceLifecycleListener mCarServiceLifecycleListener;
 
     PowerManagerHelper(Context context, @NonNull CarPowerStateListener listener) {
         mContext = context;
         mCarPowerStateListener = listener;
+        mCarServiceLifecycleListener = (car, ready) -> {
+            if (!ready) {
+                return;
+            }
+            Log.d(TAG, "Car Service connected");
+            mCarPowerManager = (CarPowerManager) car.getCarManager(Car.POWER_SERVICE);
+            if (mCarPowerManager != null) {
+                mCarPowerManager.setListener(mCarPowerStateListener);
+            } else {
+                Log.e(TAG, "CarPowerManager service not available");
+            }
+        };
     }
 
     /**
      * Connect to Car service.
      */
     void connectToCarService() {
-        mCar = Car.createCar(mContext, mCarConnectionListener);
-        if (mCar != null) {
-            mCar.connect();
-        }
-    }
-
-    /**
-     * Disconnects from Car service.
-     */
-    void disconnectFromCarService() {
-        if (mCar != null) {
-            mCar.disconnect();
-        }
-    }
-
-    private void destroyCarPowerManager() {
-        if (mCarPowerManager != null) {
-            mCarPowerManager.clearListener();
-        }
+        mCar = Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
+                mCarServiceLifecycleListener);
     }
 }
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 3014452..fb1870a 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
@@ -18,6 +18,8 @@
 
 import static android.content.DialogInterface.BUTTON_NEGATIVE;
 import static android.content.DialogInterface.BUTTON_POSITIVE;
+import static android.os.UserManager.DISALLOW_ADD_USER;
+import static android.os.UserManager.SWITCHABILITY_STATUS_OK;
 
 import android.app.ActivityManager;
 import android.app.AlertDialog;
@@ -31,7 +33,6 @@
 import android.content.IntentFilter;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
-import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.os.AsyncTask;
 import android.os.UserHandle;
@@ -66,6 +67,7 @@
     private CarUserManagerHelper mCarUserManagerHelper;
     private UserManager mUserManager;
     private Context mContext;
+    private UserIconProvider mUserIconProvider;
 
     private final BroadcastReceiver mUserUpdateReceiver = new BroadcastReceiver() {
         @Override
@@ -79,6 +81,7 @@
         mContext = context;
         mCarUserManagerHelper = new CarUserManagerHelper(mContext);
         mUserManager = UserManager.get(mContext);
+        mUserIconProvider = new UserIconProvider();
 
         addItemDecoration(new ItemSpacingDecoration(mContext.getResources().getDimensionPixelSize(
                 R.dimen.car_user_switcher_vertical_spacing_between_users)));
@@ -121,10 +124,12 @@
     }
 
     private List<UserRecord> createUserRecords(List<UserInfo> userInfoList) {
+        int fgUserId = ActivityManager.getCurrentUser();
+        UserHandle fgUserHandle = UserHandle.of(fgUserId);
         List<UserRecord> userRecords = new ArrayList<>();
 
         // If the foreground user CANNOT switch to other users, only display the foreground user.
-        if (!mCarUserManagerHelper.canForegroundUserSwitchUsers()) {
+        if (mUserManager.getUserSwitchability(fgUserHandle) != SWITCHABILITY_STATUS_OK) {
             userRecords.add(createForegroundUserRecord());
             return userRecords;
         }
@@ -135,7 +140,7 @@
                 continue;
             }
 
-            boolean isForeground = ActivityManager.getCurrentUser() == userInfo.id;
+            boolean isForeground = fgUserId == userInfo.id;
             UserRecord record = new UserRecord(userInfo, false /* isStartGuestSession */,
                     false /* isAddUser */, isForeground);
             userRecords.add(record);
@@ -145,7 +150,7 @@
         userRecords.add(createStartGuestUserRecord());
 
         // Add add user record if the foreground user can add users
-        if (mCarUserManagerHelper.canForegroundUserAddUsers()) {
+        if (!mUserManager.hasUserRestriction(DISALLOW_ADD_USER, fgUserHandle)) {
             userRecords.add(createAddUserRecord());
         }
 
@@ -250,9 +255,7 @@
         @Override
         public void onBindViewHolder(UserAdapterViewHolder holder, int position) {
             UserRecord userRecord = mUsers.get(position);
-            RoundedBitmapDrawable circleIcon = RoundedBitmapDrawableFactory.create(mRes,
-                    getUserRecordIcon(userRecord));
-            circleIcon.setCircular(true);
+            RoundedBitmapDrawable circleIcon = getCircularUserRecordIcon(userRecord);
             holder.mUserAvatarImageView.setImageDrawable(circleIcon);
             holder.mUserNameTextView.setText(userRecord.mInfo.name);
 
@@ -285,7 +288,7 @@
         }
 
         private void handleAddUserClicked() {
-            if (mCarUserManagerHelper.isUserLimitReached()) {
+            if (!mUserManager.canAddMoreUsers()) {
                 mAddUserView.setEnabled(true);
                 showMaxUserLimitReachedDialog();
             } else {
@@ -334,17 +337,20 @@
             }
         }
 
-        private Bitmap getUserRecordIcon(UserRecord userRecord) {
+        private RoundedBitmapDrawable getCircularUserRecordIcon(UserRecord userRecord) {
+            Resources resources = mContext.getResources();
+            RoundedBitmapDrawable circleIcon;
             if (userRecord.mIsStartGuestSession) {
-                return mCarUserManagerHelper.getGuestDefaultIcon();
+                circleIcon = mUserIconProvider.getRoundedGuestDefaultIcon(resources);
+            } else if (userRecord.mIsAddUser) {
+                circleIcon = RoundedBitmapDrawableFactory.create(mRes, UserIcons.convertToBitmap(
+                        mContext.getDrawable(R.drawable.car_add_circle_round)));
+                circleIcon.setCircular(true);
+            } else {
+                circleIcon = mUserIconProvider.getRoundedUserIcon(userRecord.mInfo, mContext);
             }
 
-            if (userRecord.mIsAddUser) {
-                return UserIcons.convertToBitmap(mContext
-                        .getDrawable(R.drawable.car_add_circle_round));
-            }
-
-            return mCarUserManagerHelper.getUserIcon(userRecord.mInfo);
+            return circleIcon;
         }
 
         @Override
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserIconProvider.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserIconProvider.java
new file mode 100644
index 0000000..9464eab
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserIconProvider.java
@@ -0,0 +1,116 @@
+/*
+ * 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.car;
+
+import android.annotation.UserIdInt;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import androidx.core.graphics.drawable.RoundedBitmapDrawable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+
+import com.android.internal.util.UserIcons;
+import com.android.systemui.R;
+
+/**
+ * Simple class for providing icons for users.
+ */
+public class UserIconProvider {
+    /**
+     * Gets a scaled rounded icon for the given user.  If a user does not have an icon saved, this
+     * method will default to a generic icon and update UserManager to use that icon.
+     *
+     * @param userInfo User for which the icon is requested.
+     * @param context Context to use for resources
+     * @return {@link RoundedBitmapDrawable} representing the icon for the user.
+     */
+    public RoundedBitmapDrawable getRoundedUserIcon(UserInfo userInfo, Context context) {
+        UserManager userManager = UserManager.get(context);
+        Resources res = context.getResources();
+        Bitmap icon = userManager.getUserIcon(userInfo.id);
+
+        if (icon == null) {
+            icon = assignDefaultIcon(userManager, res, userInfo);
+        }
+
+        return createScaledRoundIcon(res, icon);
+    }
+
+    /** Returns a scaled, rounded, default icon for the Guest user */
+    public RoundedBitmapDrawable getRoundedGuestDefaultIcon(Resources resources) {
+        return createScaledRoundIcon(resources, getGuestUserDefaultIcon(resources));
+    }
+
+    private RoundedBitmapDrawable createScaledRoundIcon(Resources resources, Bitmap icon) {
+        BitmapDrawable scaledIcon = scaleUserIcon(resources, icon);
+        RoundedBitmapDrawable circleIcon =
+                RoundedBitmapDrawableFactory.create(resources, scaledIcon.getBitmap());
+        circleIcon.setCircular(true);
+        return circleIcon;
+    }
+
+    /**
+     * Returns a {@link Drawable} for the given {@code icon} scaled to the appropriate size.
+     */
+    private static BitmapDrawable scaleUserIcon(Resources res, Bitmap icon) {
+        int desiredSize = res.getDimensionPixelSize(R.dimen.car_primary_icon_size);
+        Bitmap scaledIcon =
+                Bitmap.createScaledBitmap(icon, desiredSize, desiredSize, /*filter=*/ true);
+        return new BitmapDrawable(res, scaledIcon);
+    }
+
+    /**
+     * Assigns a default icon to a user according to the user's id. Handles Guest icon and non-guest
+     * user icons.
+     *
+     * @param userManager {@link UserManager} to set user icon
+     * @param resources {@link Resources} to grab icons from
+     * @param userInfo User whose avatar is set to default icon.
+     * @return Bitmap of the user icon.
+     */
+    private Bitmap assignDefaultIcon(
+            UserManager userManager, Resources resources, UserInfo userInfo) {
+        Bitmap bitmap = userInfo.isGuest()
+                ? getGuestUserDefaultIcon(resources)
+                : getUserDefaultIcon(resources, userInfo.id);
+        userManager.setUserIcon(userInfo.id, bitmap);
+        return bitmap;
+    }
+
+    /**
+     * Gets a bitmap representing the user's default avatar.
+     *
+     * @param resources The resources to pull from
+     * @param id The id of the user to get the icon for.  Pass {@link UserHandle#USER_NULL} for
+     *           Guest user.
+     * @return Default user icon
+     */
+    private Bitmap getUserDefaultIcon(Resources resources, @UserIdInt int id) {
+        return UserIcons.convertToBitmap(
+                UserIcons.getDefaultUserIcon(resources, id, /* light= */ false));
+    }
+
+    private Bitmap getGuestUserDefaultIcon(Resources resources) {
+        return getUserDefaultIcon(resources, UserHandle.USER_NULL);
+    }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java
index e81be1b..41914d2 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java
@@ -20,15 +20,13 @@
 import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
 
 import android.car.Car;
+import android.car.Car.CarServiceLifecycleListener;
 import android.car.VehicleUnit;
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.hvac.CarHvacManager;
 import android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.ServiceConnection;
 import android.os.Handler;
-import android.os.IBinder;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -54,6 +52,7 @@
     private Car mCar;
     private CarHvacManager mHvacManager;
     private HashMap<HvacKey, List<TemperatureView>> mTempComponents = new HashMap<>();
+
     /**
      * Callback for getting changes from {@link CarHvacManager} and setting the UI elements to
      * match.
@@ -85,39 +84,17 @@
                     + " zone: " + zone);
         }
     };
-    /**
-     * If the connection to car service goes away then restart it.
-     */
-    private final IBinder.DeathRecipient mRestart = new IBinder.DeathRecipient() {
-        @Override
-        public void binderDied() {
-            Log.d(TAG, "Death of HVAC triggering a restart");
-            if (mCar != null) {
-                mCar.disconnect();
-            }
-            destroyHvacManager();
-            mHandler.postDelayed(() -> mCar.connect(), BIND_TO_HVAC_RETRY_DELAY);
-        }
-    };
-    /**
-     * Registers callbacks and initializes components upon connection.
-     */
-    private ServiceConnection mServiceConnection = new ServiceConnection() {
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            try {
-                service.linkToDeath(mRestart, 0);
-                mHvacManager = (CarHvacManager) mCar.getCarManager(Car.HVAC_SERVICE);
-                mHvacManager.registerCallback(mHardwareCallback);
-                initComponents();
-            } catch (Exception e) {
-                Log.e(TAG, "Failed to correctly connect to HVAC", e);
-            }
-        }
 
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            destroyHvacManager();
+    private final CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> {
+        if (!ready) {
+            return;
+        }
+        try {
+            mHvacManager = (CarHvacManager) car.getCarManager(Car.HVAC_SERVICE);
+            mHvacManager.registerCallback(mHardwareCallback);
+            initComponents();
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to correctly connect to HVAC", e);
         }
     };
 
@@ -132,18 +109,8 @@
      */
     public void connectToCarService() {
         mHandler = new Handler();
-        mCar = Car.createCar(mContext, mServiceConnection, mHandler);
-        if (mCar != null) {
-            // note: this connect call handles the retries
-            mCar.connect();
-        }
-    }
-
-    private void destroyHvacManager() {
-        if (mHvacManager != null) {
-            mHvacManager.unregisterCallback(mHardwareCallback);
-            mHvacManager = null;
-        }
+        mCar = Car.createCar(mContext, /* handler= */ mHandler, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
+                mCarServiceLifecycleListener);
     }
 
     /**
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index 22c7c7a..09223e8 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -24,12 +24,10 @@
 import android.app.Dialog;
 import android.app.KeyguardManager;
 import android.car.Car;
-import android.car.CarNotConnectedException;
+import android.car.Car.CarServiceLifecycleListener;
 import android.car.media.CarAudioManager;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.content.ServiceConnection;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.Color;
@@ -39,7 +37,6 @@
 import android.media.AudioManager;
 import android.os.Debug;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.util.AttributeSet;
@@ -65,7 +62,6 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 
 /**
@@ -79,8 +75,6 @@
 
     private static final String XML_TAG_VOLUME_ITEMS = "carVolumeItems";
     private static final String XML_TAG_VOLUME_ITEM = "item";
-    private static final int HOVERING_TIMEOUT = 16000;
-    private static final int NORMAL_TIMEOUT = 3000;
     private static final int LISTVIEW_ANIMATION_DURATION_IN_MILLIS = 250;
     private static final int DISMISS_DELAY_IN_MILLIS = 50;
     private static final int ARROW_FADE_IN_START_DELAY_IN_MILLIS = 100;
@@ -94,12 +88,23 @@
     // Volume items in the RecyclerView.
     private final List<CarVolumeItem> mCarVolumeLineItems = new ArrayList<>();
     private final KeyguardManager mKeyguard;
+    private final int mNormalTimeout;
+    private final int mHoveringTimeout;
+
     private Window mWindow;
     private CustomDialog mDialog;
     private RecyclerView mListView;
     private CarVolumeItemAdapter mVolumeItemsAdapter;
     private Car mCar;
     private CarAudioManager mCarAudioManager;
+    private boolean mHovering;
+    private int mCurrentlyDisplayingGroupId;
+    private int mPreviouslyDisplayingGroupId;
+    private boolean mShowing;
+    private boolean mDismissing;
+    private boolean mExpanded;
+    private View mExpandIcon;
+
     private final CarAudioManager.CarVolumeCallback mVolumeChangeCallback =
             new CarAudioManager.CarVolumeCallback() {
                 @Override
@@ -129,6 +134,7 @@
                         volumeItem.progress = value;
                     }
                     if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
+                        mPreviouslyDisplayingGroupId = mCurrentlyDisplayingGroupId;
                         mCurrentlyDisplayingGroupId = groupId;
                         mHandler.obtainMessage(H.SHOW,
                                 Events.SHOW_REASON_VOLUME_CHANGED).sendToTarget();
@@ -140,81 +146,47 @@
                     // ignored
                 }
             };
-    private boolean mHovering;
-    private int mCurrentlyDisplayingGroupId;
-    private boolean mShowing;
-    private boolean mDismissing;
-    private boolean mExpanded;
-    private View mExpandIcon;
-    private final ServiceConnection mServiceConnection = new ServiceConnection() {
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            try {
-                mExpanded = false;
-                mCarAudioManager = (CarAudioManager) mCar.getCarManager(Car.AUDIO_SERVICE);
-                int volumeGroupCount = mCarAudioManager.getVolumeGroupCount();
-                // Populates volume slider items from volume groups to UI.
-                for (int groupId = 0; groupId < volumeGroupCount; groupId++) {
-                    VolumeItem volumeItem = getVolumeItemForUsages(
-                            mCarAudioManager.getUsagesForVolumeGroupId(groupId));
-                    mAvailableVolumeItems.add(volumeItem);
-                    // The first one is the default item.
-                    if (groupId == 0) {
-                        setuptListItem(0);
-                    }
-                }
 
-                // If list is already initiated, update its content.
-                if (mVolumeItemsAdapter != null) {
-                    mVolumeItemsAdapter.notifyDataSetChanged();
-                }
-                mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback);
-            } catch (CarNotConnectedException e) {
-                Log.e(TAG, "Car is not connected!", e);
+    private final CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> {
+        if (!ready) {
+            return;
+        }
+        mExpanded = false;
+        mCarAudioManager = (CarAudioManager) car.getCarManager(Car.AUDIO_SERVICE);
+        int volumeGroupCount = mCarAudioManager.getVolumeGroupCount();
+        // Populates volume slider items from volume groups to UI.
+        for (int groupId = 0; groupId < volumeGroupCount; groupId++) {
+            VolumeItem volumeItem = getVolumeItemForUsages(
+                    mCarAudioManager.getUsagesForVolumeGroupId(groupId));
+            mAvailableVolumeItems.add(volumeItem);
+            // The first one is the default item.
+            if (groupId == 0) {
+                clearAllAndSetupDefaultCarVolumeLineItem(0);
             }
         }
 
-        /**
-         * This does not get called when service is properly disconnected.
-         * So we need to also handle cleanups in destroy().
-         */
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            cleanupAudioManager();
+        // If list is already initiated, update its content.
+        if (mVolumeItemsAdapter != null) {
+            mVolumeItemsAdapter.notifyDataSetChanged();
         }
+        mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback);
     };
 
-    private void setuptListItem(int groupId) {
-        mCarVolumeLineItems.clear();
-        VolumeItem volumeItem = mAvailableVolumeItems.get(groupId);
-        volumeItem.defaultItem = true;
-        addCarVolumeListItem(volumeItem, /* volumeGroupId = */ groupId,
-                R.drawable.car_ic_keyboard_arrow_down, new ExpandIconListener()
-        );
-    }
-
     public CarVolumeDialogImpl(Context context) {
         mContext = context;
         mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
-        mCar = Car.createCar(mContext, mServiceConnection);
+        mNormalTimeout = mContext.getResources().getInteger(
+                R.integer.car_volume_dialog_display_normal_timeout);
+        mHoveringTimeout = mContext.getResources().getInteger(
+                R.integer.car_volume_dialog_display_hovering_timeout);
     }
 
     private static int getSeekbarValue(CarAudioManager carAudioManager, int volumeGroupId) {
-        try {
-            return carAudioManager.getGroupVolume(volumeGroupId);
-        } catch (CarNotConnectedException e) {
-            Log.e(TAG, "Car is not connected!", e);
-        }
-        return 0;
+        return carAudioManager.getGroupVolume(volumeGroupId);
     }
 
     private static int getMaxSeekbarValue(CarAudioManager carAudioManager, int volumeGroupId) {
-        try {
-            return carAudioManager.getGroupMaxVolume(volumeGroupId);
-        } catch (CarNotConnectedException e) {
-            Log.e(TAG, "Car is not connected!", e);
-        }
-        return 0;
+        return carAudioManager.getGroupMaxVolume(volumeGroupId);
     }
 
     /**
@@ -224,18 +196,21 @@
     @Override
     public void init(int windowType, Callback callback) {
         initDialog();
-
-        mCar.connect();
+        mCar = Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
+                mCarServiceLifecycleListener);
     }
 
     @Override
     public void destroy() {
-        mHandler.removeCallbacksAndMessages(null);
+        mHandler.removeCallbacksAndMessages(/* token= */ null);
 
         cleanupAudioManager();
         // unregisterVolumeCallback is not being called when disconnect car, so we manually cleanup
         // audio manager beforehand.
-        mCar.disconnect();
+        if (mCar != null) {
+            mCar.disconnect();
+            mCar = null;
+        }
     }
 
     private void initDialog() {
@@ -303,19 +278,36 @@
 
         mHandler.removeMessages(H.SHOW);
         mHandler.removeMessages(H.DISMISS);
+
         rescheduleTimeoutH();
+
         // Refresh the data set before showing.
         mVolumeItemsAdapter.notifyDataSetChanged();
+
         if (mShowing) {
+            if (mPreviouslyDisplayingGroupId == mCurrentlyDisplayingGroupId || mExpanded) {
+                return;
+            }
+
+            clearAllAndSetupDefaultCarVolumeLineItem(mCurrentlyDisplayingGroupId);
             return;
         }
+
         mShowing = true;
-        setuptListItem(mCurrentlyDisplayingGroupId);
+        clearAllAndSetupDefaultCarVolumeLineItem(mCurrentlyDisplayingGroupId);
         mDialog.show();
         Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
     }
 
-    private void rescheduleTimeoutH() {
+    private void clearAllAndSetupDefaultCarVolumeLineItem(int groupId) {
+        mCarVolumeLineItems.clear();
+        VolumeItem volumeItem = mAvailableVolumeItems.get(groupId);
+        volumeItem.defaultItem = true;
+        addCarVolumeListItem(volumeItem, /* volumeGroupId = */ groupId,
+                R.drawable.car_ic_keyboard_arrow_down, new ExpandIconListener());
+    }
+
+    protected void rescheduleTimeoutH() {
         mHandler.removeMessages(H.DISMISS);
         final int timeout = computeTimeoutH();
         mHandler.sendMessageDelayed(mHandler
@@ -327,7 +319,7 @@
     }
 
     private int computeTimeoutH() {
-        return mHovering ? HOVERING_TIMEOUT : NORMAL_TIMEOUT;
+        return mHovering ? mHoveringTimeout : mNormalTimeout;
     }
 
     private void dismissH(int reason) {
@@ -389,12 +381,13 @@
                 if (XML_TAG_VOLUME_ITEM.equals(parser.getName())) {
                     TypedArray item = mContext.getResources().obtainAttributes(
                             attrs, R.styleable.carVolumeItems_item);
-                    int usage = item.getInt(R.styleable.carVolumeItems_item_usage, -1);
+                    int usage = item.getInt(R.styleable.carVolumeItems_item_usage,
+                            /* defValue= */ -1);
                     if (usage >= 0) {
                         VolumeItem volumeItem = new VolumeItem();
                         volumeItem.rank = rank;
-                        volumeItem.icon = item.getResourceId(R.styleable.carVolumeItems_item_icon,
-                                0);
+                        volumeItem.icon = item.getResourceId(
+                                R.styleable.carVolumeItems_item_icon, /* defValue= */ 0);
                         mVolumeItems.put(usage, volumeItem);
                         rank++;
                     }
@@ -419,22 +412,22 @@
         return result;
     }
 
-    private CarVolumeItem addCarVolumeListItem(VolumeItem volumeItem, int volumeGroupId,
-            int supplementalIconId,
+    private CarVolumeItem createCarVolumeListItem(VolumeItem volumeItem, int volumeGroupId,
+            Drawable supplementalIcon, int seekbarProgressValue,
             @Nullable View.OnClickListener supplementalIconOnClickListener) {
         CarVolumeItem carVolumeItem = new CarVolumeItem();
         carVolumeItem.setMax(getMaxSeekbarValue(mCarAudioManager, volumeGroupId));
-        int color = mContext.getResources().getColor(R.color.car_volume_dialog_tint);
-        int progress = getSeekbarValue(mCarAudioManager, volumeGroupId);
-        carVolumeItem.setProgress(progress);
+        carVolumeItem.setProgress(seekbarProgressValue);
         carVolumeItem.setOnSeekBarChangeListener(
                 new CarVolumeDialogImpl.VolumeSeekBarChangeListener(volumeGroupId,
                         mCarAudioManager));
-        Drawable primaryIcon = mContext.getResources().getDrawable(volumeItem.icon);
+        carVolumeItem.setGroupId(volumeGroupId);
+
+        int color = mContext.getColor(R.color.car_volume_dialog_tint);
+        Drawable primaryIcon = mContext.getDrawable(volumeItem.icon);
         primaryIcon.mutate().setTint(color);
         carVolumeItem.setPrimaryIcon(primaryIcon);
-        if (supplementalIconId != 0) {
-            Drawable supplementalIcon = mContext.getResources().getDrawable(supplementalIconId);
+        if (supplementalIcon != null) {
             supplementalIcon.mutate().setTint(color);
             carVolumeItem.setSupplementalIcon(supplementalIcon,
                     /* showSupplementalIconDivider= */ true);
@@ -443,21 +436,23 @@
             carVolumeItem.setSupplementalIcon(/* drawable= */ null,
                     /* showSupplementalIconDivider= */ false);
         }
-        carVolumeItem.setGroupId(volumeGroupId);
-        mCarVolumeLineItems.add(carVolumeItem);
+
         volumeItem.carVolumeItem = carVolumeItem;
-        volumeItem.progress = progress;
+        volumeItem.progress = seekbarProgressValue;
+
         return carVolumeItem;
     }
 
-    private VolumeItem findVolumeItem(CarVolumeItem targetItem) {
-        for (int i = 0; i < mVolumeItems.size(); ++i) {
-            VolumeItem volumeItem = mVolumeItems.valueAt(i);
-            if (volumeItem.carVolumeItem == targetItem) {
-                return volumeItem;
-            }
-        }
-        return null;
+    private CarVolumeItem addCarVolumeListItem(VolumeItem volumeItem, int volumeGroupId,
+            int supplementalIconId,
+            @Nullable View.OnClickListener supplementalIconOnClickListener) {
+        int seekbarProgressValue = getSeekbarValue(mCarAudioManager, volumeGroupId);
+        Drawable supplementalIcon = supplementalIconId == 0 ? null : mContext.getDrawable(
+                supplementalIconId);
+        CarVolumeItem carVolumeItem = createCarVolumeListItem(volumeItem, volumeGroupId,
+                supplementalIcon, seekbarProgressValue, supplementalIconOnClickListener);
+        mCarVolumeLineItems.add(carVolumeItem);
+        return carVolumeItem;
     }
 
     private void cleanupAudioManager() {
@@ -553,21 +548,15 @@
             for (int groupId = 0; groupId < mAvailableVolumeItems.size(); ++groupId) {
                 if (groupId != mCurrentlyDisplayingGroupId) {
                     VolumeItem volumeItem = mAvailableVolumeItems.get(groupId);
-                    addCarVolumeListItem(volumeItem, groupId, 0, null);
+                    addCarVolumeListItem(volumeItem, groupId, /* supplementalIconId= */ 0,
+                            /* supplementalIconOnClickListener= */ null);
                 }
             }
             inAnimator = AnimatorInflater.loadAnimator(
                     mContext, R.anim.car_arrow_fade_in_rotate_up);
 
         } else {
-            // Only keeping the default stream if it is not expended.
-            Iterator itr = mCarVolumeLineItems.iterator();
-            while (itr.hasNext()) {
-                CarVolumeItem carVolumeItem = (CarVolumeItem) itr.next();
-                if (carVolumeItem.getGroupId() != mCurrentlyDisplayingGroupId) {
-                    itr.remove();
-                }
-            }
+            clearAllAndSetupDefaultCarVolumeLineItem(mCurrentlyDisplayingGroupId);
             inAnimator = AnimatorInflater.loadAnimator(
                     mContext, R.anim.car_arrow_fade_in_rotate_down);
         }
@@ -605,18 +594,14 @@
                 // sent back down again.
                 return;
             }
-            try {
-                if (mCarAudioManager == null) {
-                    Log.w(TAG, "Ignoring volume change event because the car isn't connected");
-                    return;
-                }
-                mAvailableVolumeItems.get(mVolumeGroupId).progress = progress;
-                mAvailableVolumeItems.get(
-                        mVolumeGroupId).carVolumeItem.setProgress(progress);
-                mCarAudioManager.setGroupVolume(mVolumeGroupId, progress, 0);
-            } catch (CarNotConnectedException e) {
-                Log.e(TAG, "Car is not connected!", e);
+            if (mCarAudioManager == null) {
+                Log.w(TAG, "Ignoring volume change event because the car isn't connected");
+                return;
             }
+            mAvailableVolumeItems.get(mVolumeGroupId).progress = progress;
+            mAvailableVolumeItems.get(
+                    mVolumeGroupId).carVolumeItem.setProgress(progress);
+            mCarAudioManager.setGroupVolume(mVolumeGroupId, progress, 0);
         }
 
         @Override
diff --git a/packages/CarSystemUI/tests/Android.mk b/packages/CarSystemUI/tests/Android.mk
new file mode 100644
index 0000000..1366568
--- /dev/null
+++ b/packages/CarSystemUI/tests/Android.mk
@@ -0,0 +1,88 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_USE_AAPT2 := true
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JACK_FLAGS := --multi-dex native
+LOCAL_DX_FLAGS := --multi-dex
+
+LOCAL_PACKAGE_NAME := CarSystemUITests
+LOCAL_PRIVATE_PLATFORM_APIS := true
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+LOCAL_STATIC_ANDROID_LIBRARIES := \
+    CarSystemUI-tests
+
+LOCAL_MULTILIB := both
+
+LOCAL_JNI_SHARED_LIBRARIES := \
+    libdexmakerjvmtiagent \
+    libmultiplejvmtiagentsinterferenceagent
+
+LOCAL_JAVA_LIBRARIES := \
+    android.test.runner \
+    telephony-common \
+    android.test.base \
+
+LOCAL_AAPT_FLAGS := --extra-packages com.android.systemui
+
+# sign this with platform cert, so this test is allowed to inject key events into
+# UI it doesn't own. This is necessary to allow screenshots to be taken
+LOCAL_CERTIFICATE := platform
+
+# Provide jack a list of classes to exclude from code coverage.
+# This is needed because the CarSystemUITests compile CarSystemUI source directly, rather than using
+# LOCAL_INSTRUMENTATION_FOR := CarSystemUI.
+#
+# We want to exclude the test classes from code coverage measurements, but they share the same
+# package as the rest of SystemUI so they can't be easily filtered by package name.
+#
+# Generate a comma separated list of patterns based on the test source files under src/
+# SystemUI classes are in ../src/ so they won't be excluded.
+# Example:
+#   Input files: src/com/android/systemui/Test.java src/com/android/systemui/AnotherTest.java
+#   Generated exclude list: com.android.systemui.Test*,com.android.systemui.AnotherTest*
+
+# Filter all src files under src/ to just java files
+local_java_files := $(filter %.java,$(call all-java-files-under, src))
+
+# 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)))
+local_comma := ,
+local_empty :=
+local_space := $(local_empty) $(local_empty)
+
+# Convert class name list to jacoco exclude list
+# This appends a * to all classes and replace the space separators with commas.
+jacoco_exclude := $(subst $(space),$(comma),$(patsubst %,%*,$(local_classes)))
+
+LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.systemui.*,com.android.keyguard.*
+LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude)
+
+ifeq ($(EXCLUDE_SYSTEMUI_TESTS),)
+    include $(BUILD_PACKAGE)
+endif
+
+# Reset variables
+local_java_files :=
+local_classes :=
+local_comma :=
+local_space :=
+jacoco_exclude :=
diff --git a/packages/CarSystemUI/tests/AndroidManifest.xml b/packages/CarSystemUI/tests/AndroidManifest.xml
new file mode 100644
index 0000000..a74bb56
--- /dev/null
+++ b/packages/CarSystemUI/tests/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          android:sharedUserId="android.uid.system"
+          package="com.android.systemui.tests">
+
+    <application android:debuggable="true" android:largeHeap="true">
+        <uses-library android:name="android.test.runner" />
+
+        <provider
+            android:name="androidx.lifecycle.ProcessLifecycleOwnerInitializer"
+            tools:replace="android:authorities"
+            android:authorities="${applicationId}.lifecycle-tests"
+            android:exported="false"
+            android:enabled="false"
+            android:multiprocess="true" />
+    </application>
+
+    <instrumentation android:name="android.testing.TestableInstrumentation"
+        android:targetPackage="com.android.systemui.tests"
+        android:label="Tests for CarSystemUI">
+    </instrumentation>
+</manifest>
diff --git a/packages/CarSystemUI/tests/AndroidTest.xml b/packages/CarSystemUI/tests/AndroidTest.xml
new file mode 100644
index 0000000..8685632
--- /dev/null
+++ b/packages/CarSystemUI/tests/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<configuration description="Runs Tests for CarSystemUI.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="CarSystemUITests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="framework-base-presubmit" />
+    <option name="test-tag" value="CarSystemUITests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.systemui.tests" />
+        <option name="runner" value="android.testing.TestableInstrumentation" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
diff --git a/packages/CarSystemUI/tests/res/values/config.xml b/packages/CarSystemUI/tests/res/values/config.xml
new file mode 100644
index 0000000..0d08ac2
--- /dev/null
+++ b/packages/CarSystemUI/tests/res/values/config.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<resources>
+    <!-- Configure which system ui bars should be displayed.
+         These can be overwritten within the tests. -->
+    <bool name="config_enableLeftNavigationBar">false</bool>
+    <bool name="config_enableRightNavigationBar">false</bool>
+    <bool name="config_enableBottomNavigationBar">false</bool>
+</resources>
diff --git a/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java b/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
new file mode 100644
index 0000000..fe59cbf
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
@@ -0,0 +1,214 @@
+/*
+ * 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;
+
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+import android.testing.AndroidTestingRunner;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.internal.runner.ClassPathScanner;
+import androidx.test.internal.runner.ClassPathScanner.ChainedClassNameFilter;
+import androidx.test.internal.runner.ClassPathScanner.ExternalClassNameFilter;
+
+import com.android.systemui.SysuiBaseFragmentTest;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * This is named AAAPlusPlusVerifySysuiRequiredTestPropertiesTest for two reasons.
+ * a) Its so awesome it deserves an AAA++
+ * b) It should run first to draw attention to itself.
+ *
+ * For trues though: this test verifies that all the sysui tests extend the right classes.
+ * This matters because including tests with different context implementations in the same
+ * test suite causes errors, such as the incorrect settings provider being cached.
+ * For an example, see {@link com.android.systemui.DependencyTest}.
+ */
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class AAAPlusPlusVerifySysuiRequiredTestPropertiesTest extends SysuiTestCase {
+
+    private static final String TAG = "AAA++VerifyTest";
+
+    private static final Class[] BASE_CLS_WHITELIST = {
+            SysuiTestCase.class,
+            SysuiBaseFragmentTest.class,
+    };
+
+    private static final Class[] SUPPORTED_SIZES = {
+            SmallTest.class,
+            MediumTest.class,
+            LargeTest.class,
+            android.test.suitebuilder.annotation.SmallTest.class,
+            android.test.suitebuilder.annotation.MediumTest.class,
+            android.test.suitebuilder.annotation.LargeTest.class,
+    };
+
+    @Test
+    public void testAllClassInheritance() throws Throwable {
+        ArrayList<String> fails = new ArrayList<>();
+        for (String className : getClassNamesFromClassPath()) {
+            Class<?> cls = Class.forName(className, false, this.getClass().getClassLoader());
+            if (!isTestClass(cls)) continue;
+
+            boolean hasParent = false;
+            for (Class<?> parent : BASE_CLS_WHITELIST) {
+                if (parent.isAssignableFrom(cls)) {
+                    hasParent = true;
+                    break;
+                }
+            }
+            boolean hasSize = hasSize(cls);
+            if (!hasSize) {
+                fails.add(cls.getName() + " does not have size annotation, such as @SmallTest");
+            }
+            if (!hasParent) {
+                fails.add(cls.getName() + " does not extend any of " + getClsStr());
+            }
+        }
+
+        assertThat("All sysui test classes must have size and extend one of " + getClsStr(),
+                fails, is(empty()));
+    }
+
+    private boolean hasSize(Class<?> cls) {
+        for (int i = 0; i < SUPPORTED_SIZES.length; i++) {
+            if (cls.getDeclaredAnnotation(SUPPORTED_SIZES[i]) != null) return true;
+        }
+        return false;
+    }
+
+    private Collection<String> getClassNamesFromClassPath() {
+        ClassPathScanner scanner = new ClassPathScanner(mContext.getPackageCodePath());
+
+        ChainedClassNameFilter filter = new ChainedClassNameFilter();
+
+        filter.add(new ExternalClassNameFilter());
+        filter.add(s -> s.startsWith("com.android.systemui")
+                || s.startsWith("com.android.keyguard"));
+
+        try {
+            return scanner.getClassPathEntries(filter);
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to scan classes", e);
+        }
+        return Collections.emptyList();
+    }
+
+    private String getClsStr() {
+        return TextUtils.join(",", Arrays.asList(BASE_CLS_WHITELIST)
+                .stream().map(cls -> cls.getSimpleName()).toArray());
+    }
+
+    /**
+     * Determines if given class is a valid test class.
+     *
+     * @return <code>true</code> if loadedClass is a test
+     */
+    private boolean isTestClass(Class<?> loadedClass) {
+        try {
+            if (Modifier.isAbstract(loadedClass.getModifiers())) {
+                logDebug(String.format("Skipping abstract class %s: not a test",
+                        loadedClass.getName()));
+                return false;
+            }
+            // TODO: try to find upstream junit calls to replace these checks
+            if (junit.framework.Test.class.isAssignableFrom(loadedClass)) {
+                // ensure that if a TestCase, it has at least one test method otherwise
+                // TestSuite will throw error
+                if (junit.framework.TestCase.class.isAssignableFrom(loadedClass)) {
+                    return hasJUnit3TestMethod(loadedClass);
+                }
+                return true;
+            }
+            // TODO: look for a 'suite' method?
+            if (loadedClass.isAnnotationPresent(RunWith.class)) {
+                return true;
+            }
+            for (Method testMethod : loadedClass.getMethods()) {
+                if (testMethod.isAnnotationPresent(Test.class)) {
+                    return true;
+                }
+            }
+            logDebug(String.format("Skipping class %s: not a test", loadedClass.getName()));
+            return false;
+        } catch (Exception e) {
+            // Defensively catch exceptions - Will throw runtime exception if it cannot load
+            // methods.
+            // For earlier versions of Android (Pre-ICS), Dalvik might try to initialize a class
+            // during getMethods(), fail to do so, hide the error and throw a NoSuchMethodException.
+            // Since the java.lang.Class.getMethods does not declare such an exception, resort to a
+            // generic catch all.
+            // For ICS+, Dalvik will throw a NoClassDefFoundException.
+            Log.w(TAG, String.format("%s in isTestClass for %s", e.toString(),
+                    loadedClass.getName()));
+            return false;
+        } catch (Error e) {
+            // defensively catch Errors too
+            Log.w(TAG, String.format("%s in isTestClass for %s", e.toString(),
+                    loadedClass.getName()));
+            return false;
+        }
+    }
+
+    private boolean hasJUnit3TestMethod(Class<?> loadedClass) {
+        for (Method testMethod : loadedClass.getMethods()) {
+            if (isPublicTestMethod(testMethod)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // copied from junit.framework.TestSuite
+    private boolean isPublicTestMethod(Method m) {
+        return isTestMethod(m) && Modifier.isPublic(m.getModifiers());
+    }
+
+    // copied from junit.framework.TestSuite
+    private boolean isTestMethod(Method m) {
+        return m.getParameterTypes().length == 0 && m.getName().startsWith("test")
+                && m.getReturnType().equals(Void.TYPE);
+    }
+
+    /**
+     * Utility method for logging debug messages. Only actually logs a message if TAG is marked
+     * as loggable to limit log spam during normal use.
+     */
+    private void logDebug(String msg) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, msg);
+        }
+    }
+}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java
new file mode 100644
index 0000000..901d200
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java
@@ -0,0 +1,408 @@
+/*
+ * 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.navigationbar.car;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableResources;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.statusbar.car.hvac.HvacController;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import dagger.Lazy;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class CarNavigationBarControllerTest extends SysuiTestCase {
+
+    private CarNavigationBarController mCarNavigationBar;
+    private NavigationBarViewFactory mNavigationBarViewFactory;
+    private Lazy<HvacController> mHvacControllerLazy;
+    private TestableResources mTestableResources;
+
+    @Mock
+    private HvacController mHvacController;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mNavigationBarViewFactory = new NavigationBarViewFactory(mContext);
+        mHvacControllerLazy = () -> mHvacController;
+        mTestableResources = mContext.getOrCreateTestableResources();
+
+        // Needed to inflate top navigation bar.
+        mDependency.injectMockDependency(DarkIconDispatcher.class);
+        mDependency.injectMockDependency(StatusBarIconController.class);
+    }
+
+    @Test
+    public void testConnectToHvac_callsConnect() {
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+
+        mCarNavigationBar.connectToHvac();
+
+        verify(mHvacController).connectToCarService();
+    }
+
+    @Test
+    public void testRemoveAllFromHvac_callsRemoveAll() {
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+
+        mCarNavigationBar.removeAllFromHvac();
+
+        verify(mHvacController).removeAllComponents();
+    }
+
+    @Test
+    public void testGetBottomWindow_bottomDisabled_returnsNull() {
+        mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, false);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+
+        ViewGroup window = mCarNavigationBar.getBottomWindow();
+
+        assertThat(window).isNull();
+    }
+
+    @Test
+    public void testGetBottomWindow_bottomEnabled_returnsWindow() {
+        mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+
+        ViewGroup window = mCarNavigationBar.getBottomWindow();
+
+        assertThat(window).isNotNull();
+    }
+
+    @Test
+    public void testGetBottomWindow_bottomEnabled_calledTwice_returnsSameWindow() {
+        mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+
+        ViewGroup window1 = mCarNavigationBar.getBottomWindow();
+        ViewGroup window2 = mCarNavigationBar.getBottomWindow();
+
+        assertThat(window1).isEqualTo(window2);
+    }
+
+    @Test
+    public void testGetLeftWindow_leftDisabled_returnsNull() {
+        mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, false);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+        ViewGroup window = mCarNavigationBar.getLeftWindow();
+        assertThat(window).isNull();
+    }
+
+    @Test
+    public void testGetLeftWindow_leftEnabled_returnsWindow() {
+        mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+
+        ViewGroup window = mCarNavigationBar.getLeftWindow();
+
+        assertThat(window).isNotNull();
+    }
+
+    @Test
+    public void testGetLeftWindow_leftEnabled_calledTwice_returnsSameWindow() {
+        mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+
+        ViewGroup window1 = mCarNavigationBar.getLeftWindow();
+        ViewGroup window2 = mCarNavigationBar.getLeftWindow();
+
+        assertThat(window1).isEqualTo(window2);
+    }
+
+    @Test
+    public void testGetRightWindow_rightDisabled_returnsNull() {
+        mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, false);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+
+        ViewGroup window = mCarNavigationBar.getRightWindow();
+
+        assertThat(window).isNull();
+    }
+
+    @Test
+    public void testGetRightWindow_rightEnabled_returnsWindow() {
+        mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+
+        ViewGroup window = mCarNavigationBar.getRightWindow();
+
+        assertThat(window).isNotNull();
+    }
+
+    @Test
+    public void testGetRightWindow_rightEnabled_calledTwice_returnsSameWindow() {
+        mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+
+        ViewGroup window1 = mCarNavigationBar.getRightWindow();
+        ViewGroup window2 = mCarNavigationBar.getRightWindow();
+
+        assertThat(window1).isEqualTo(window2);
+    }
+
+    @Test
+    public void testSetBottomWindowVisibility_setTrue_isVisible() {
+        mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+
+        ViewGroup window = mCarNavigationBar.getBottomWindow();
+        mCarNavigationBar.setBottomWindowVisibility(View.VISIBLE);
+
+        assertThat(window.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void testSetBottomWindowVisibility_setFalse_isGone() {
+        mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+
+        ViewGroup window = mCarNavigationBar.getBottomWindow();
+        mCarNavigationBar.setBottomWindowVisibility(View.GONE);
+
+        assertThat(window.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void testSetLeftWindowVisibility_setTrue_isVisible() {
+        mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+
+        ViewGroup window = mCarNavigationBar.getLeftWindow();
+        mCarNavigationBar.setLeftWindowVisibility(View.VISIBLE);
+
+        assertThat(window.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void testSetLeftWindowVisibility_setFalse_isGone() {
+        mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+
+        ViewGroup window = mCarNavigationBar.getLeftWindow();
+        mCarNavigationBar.setLeftWindowVisibility(View.GONE);
+
+        assertThat(window.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void testSetRightWindowVisibility_setTrue_isVisible() {
+        mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+
+        ViewGroup window = mCarNavigationBar.getRightWindow();
+        mCarNavigationBar.setRightWindowVisibility(View.VISIBLE);
+
+        assertThat(window.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void testSetRightWindowVisibility_setFalse_isGone() {
+        mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+
+        ViewGroup window = mCarNavigationBar.getRightWindow();
+        mCarNavigationBar.setRightWindowVisibility(View.GONE);
+
+        assertThat(window.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void testRegisterBottomBarTouchListener_createViewFirst_registrationSuccessful() {
+        mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+
+        CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
+        View.OnTouchListener controller = bottomBar.getStatusBarWindowTouchListener();
+        assertThat(controller).isNull();
+        mCarNavigationBar.registerBottomBarTouchListener(mock(View.OnTouchListener.class));
+        controller = bottomBar.getStatusBarWindowTouchListener();
+
+        assertThat(controller).isNotNull();
+    }
+
+    @Test
+    public void testRegisterBottomBarTouchListener_registerFirst_registrationSuccessful() {
+        mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+
+        mCarNavigationBar.registerBottomBarTouchListener(mock(View.OnTouchListener.class));
+        CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
+        View.OnTouchListener controller = bottomBar.getStatusBarWindowTouchListener();
+
+        assertThat(controller).isNotNull();
+    }
+
+    @Test
+    public void testRegisterNotificationController_createViewFirst_registrationSuccessful() {
+        mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+
+        CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
+        CarNavigationBarController.NotificationsShadeController controller =
+                bottomBar.getNotificationsPanelController();
+        assertThat(controller).isNull();
+        mCarNavigationBar.registerNotificationController(
+                mock(CarNavigationBarController.NotificationsShadeController.class));
+        controller = bottomBar.getNotificationsPanelController();
+
+        assertThat(controller).isNotNull();
+    }
+
+    @Test
+    public void testRegisterNotificationController_registerFirst_registrationSuccessful() {
+        mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+
+        mCarNavigationBar.registerNotificationController(
+                mock(CarNavigationBarController.NotificationsShadeController.class));
+        CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
+        CarNavigationBarController.NotificationsShadeController controller =
+                bottomBar.getNotificationsPanelController();
+
+        assertThat(controller).isNotNull();
+    }
+
+    @Test
+    public void testShowAllKeyguardButtons_bottomEnabled_bottomKeyguardButtonsVisible() {
+        mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+        CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
+        View bottomKeyguardButtons = bottomBar.findViewById(R.id.lock_screen_nav_buttons);
+
+        mCarNavigationBar.showAllKeyguardButtons(/* isSetUp= */ true);
+
+        assertThat(bottomKeyguardButtons.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void testShowAllKeyguardButtons_bottomEnabled_bottomNavButtonsGone() {
+        mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+        CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
+        View bottomButtons = bottomBar.findViewById(R.id.nav_buttons);
+
+        mCarNavigationBar.showAllKeyguardButtons(/* isSetUp= */ true);
+
+        assertThat(bottomButtons.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void testHideAllKeyguardButtons_bottomEnabled_bottomKeyguardButtonsGone() {
+        mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+        CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
+        View bottomKeyguardButtons = bottomBar.findViewById(R.id.lock_screen_nav_buttons);
+
+        mCarNavigationBar.showAllKeyguardButtons(/* isSetUp= */ true);
+        assertThat(bottomKeyguardButtons.getVisibility()).isEqualTo(View.VISIBLE);
+        mCarNavigationBar.hideAllKeyguardButtons(/* isSetUp= */ true);
+
+        assertThat(bottomKeyguardButtons.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void testHideAllKeyguardButtons_bottomEnabled_bottomNavButtonsVisible() {
+        mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+        CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
+        View bottomButtons = bottomBar.findViewById(R.id.nav_buttons);
+
+        mCarNavigationBar.showAllKeyguardButtons(/* isSetUp= */ true);
+        assertThat(bottomButtons.getVisibility()).isEqualTo(View.GONE);
+        mCarNavigationBar.hideAllKeyguardButtons(/* isSetUp= */ true);
+
+        assertThat(bottomButtons.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void testToggleAllNotificationsUnseenIndicator_bottomEnabled_hasUnseen_setCorrectly() {
+        mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+        CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
+        CarNavigationButton notifications = bottomBar.findViewById(R.id.notifications);
+
+        boolean hasUnseen = true;
+        mCarNavigationBar.toggleAllNotificationsUnseenIndicator(/* isSetUp= */ true,
+                hasUnseen);
+
+        assertThat(notifications.getUnseen()).isTrue();
+    }
+
+    @Test
+    public void testToggleAllNotificationsUnseenIndicator_bottomEnabled_noUnseen_setCorrectly() {
+        mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
+        mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory,
+                mHvacControllerLazy);
+        CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
+        CarNavigationButton notifications = bottomBar.findViewById(R.id.notifications);
+
+        boolean hasUnseen = false;
+        mCarNavigationBar.toggleAllNotificationsUnseenIndicator(/* isSetUp= */ true,
+                hasUnseen);
+
+        assertThat(notifications.getUnseen()).isFalse();
+    }
+}
diff --git a/packages/CtsShim/Android.bp b/packages/CtsShim/Android.bp
new file mode 100644
index 0000000..7728464
--- /dev/null
+++ b/packages/CtsShim/Android.bp
@@ -0,0 +1,74 @@
+//
+// 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.
+//
+
+//##########################################################
+// Variant: Privileged app
+
+android_app_import {
+    name: "CtsShimPrivPrebuilt",
+
+    // this needs to be a privileged application
+    privileged: true,
+
+    // Make sure the build system doesn't try to resign the APK
+    dex_preopt: {
+        enabled: false,
+    },
+
+    arch: {
+        arm: {
+            apk: "apk/arm/CtsShimPriv.apk",
+        },
+        arm64: {
+            apk: "apk/arm/CtsShimPriv.apk",
+        },
+        x86: {
+            apk: "apk/x86/CtsShimPriv.apk",
+        },
+        x86_64: {
+            apk: "apk/x86/CtsShimPriv.apk",
+        },
+    },
+    presigned: true,
+}
+
+//##########################################################
+// Variant: System app
+
+android_app_import {
+    name: "CtsShimPrebuilt",
+
+    // Make sure the build system doesn't try to resign the APK
+    dex_preopt: {
+        enabled: false,
+    },
+
+    arch: {
+        arm: {
+            apk: "apk/arm/CtsShim.apk",
+        },
+        arm64: {
+            apk: "apk/arm/CtsShim.apk",
+        },
+        x86: {
+            apk: "apk/x86/CtsShim.apk",
+        },
+        x86_64: {
+            apk: "apk/x86/CtsShim.apk",
+        },
+    },
+    presigned: true,
+}
diff --git a/packages/CtsShim/Android.mk b/packages/CtsShim/Android.mk
deleted file mode 100644
index 12972f1..0000000
--- a/packages/CtsShim/Android.mk
+++ /dev/null
@@ -1,64 +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)
-
-###########################################################
-# Variant: Privileged app
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := CtsShimPrivPrebuilt
-LOCAL_MODULE_TAGS := optional
-# this needs to be a privileged application
-LOCAL_PRIVILEGED_MODULE := true
-LOCAL_MODULE_CLASS := APPS
-LOCAL_BUILT_MODULE_STEM := package.apk
-# Make sure the build system doesn't try to resign the APK
-LOCAL_CERTIFICATE := PRESIGNED
-LOCAL_DEX_PREOPT := false
-LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64
-
-LOCAL_SRC_FILES_arm := apk/arm/CtsShimPriv.apk
-LOCAL_SRC_FILES_arm64 := apk/arm/CtsShimPriv.apk
-LOCAL_SRC_FILES_x86 := apk/x86/CtsShimPriv.apk
-LOCAL_SRC_FILES_x86_64 := apk/x86/CtsShimPriv.apk
-
-include $(BUILD_PREBUILT)
-
-
-###########################################################
-# Variant: System app
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := CtsShimPrebuilt
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := APPS
-LOCAL_BUILT_MODULE_STEM := package.apk
-# Make sure the build system doesn't try to resign the APK
-LOCAL_CERTIFICATE := PRESIGNED
-LOCAL_DEX_PREOPT := false
-LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64
-
-LOCAL_SRC_FILES_arm := apk/arm/CtsShim.apk
-LOCAL_SRC_FILES_arm64 := apk/arm/CtsShim.apk
-LOCAL_SRC_FILES_x86 := apk/x86/CtsShim.apk
-LOCAL_SRC_FILES_x86_64 := apk/x86/CtsShim.apk
-
-include $(BUILD_PREBUILT)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/CtsShim/build/Android.bp b/packages/CtsShim/build/Android.bp
new file mode 100644
index 0000000..ede1fab
--- /dev/null
+++ b/packages/CtsShim/build/Android.bp
@@ -0,0 +1,117 @@
+// 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.
+
+// Build rules to build shim apks.
+
+//##########################################################
+// Variant: Privileged app upgrade
+
+android_app {
+    name: "CtsShimPrivUpgrade",
+    // this needs to be a privileged application
+    privileged: true,
+
+    sdk_version: "current",
+    optimize: {
+        enabled: false,
+    },
+    dex_preopt: {
+        enabled: false,
+    },
+
+    manifest: "shim_priv_upgrade/AndroidManifest.xml",
+
+    compile_multilib: "both",
+    jni_libs: ["libshim_jni"],
+}
+
+genrule {
+  name: "generate_priv_manifest",
+  srcs: [
+    "shim_priv/AndroidManifest.xml",
+    ":CtsShimPrivUpgrade"
+  ],
+  out: ["AndroidManifest.xml"],
+  cmd: "sed -e s/__HASH__/`sha512sum -b $(location :CtsShimPrivUpgrade) | cut -d' ' -f1`/ $(location shim_priv/AndroidManifest.xml) > $(out)",
+}
+
+//##########################################################
+// Variant: Privileged app
+
+android_app {
+    name: "CtsShimPriv",
+    // this needs to be a privileged application
+    privileged: true,
+
+    sdk_version: "current",
+    optimize: {
+        enabled: false,
+    },
+    dex_preopt: {
+        enabled: false,
+    },
+
+    manifest: ":generate_priv_manifest",
+
+    compile_multilib: "both",
+    jni_libs: ["libshim_jni"],
+    // Explicitly uncompress native libs rather than letting the build system doing it and destroy the
+    // v2/v3 signature.
+    use_embedded_native_libs: true,
+}
+
+//##########################################################
+// Variant: Privileged app upgrade w/ the wrong SHA
+
+android_app {
+    name: "CtsShimPrivUpgradeWrongSHA",
+    // this needs to be a privileged application
+    privileged: true,
+
+    sdk_version: "current",
+    optimize: {
+        enabled: false,
+    },
+    dex_preopt: {
+        enabled: false,
+    },
+    // anything to make this package's SHA different from CtsShimPrivUpgrade
+    aaptflags: [
+        "--version-name",
+        "WrongSHA",
+    ],
+
+    manifest: "shim_priv_upgrade/AndroidManifest.xml",
+
+    compile_multilib: "both",
+    jni_libs: ["libshim_jni"],
+
+}
+
+//##########################################################
+// Variant: System app
+
+android_app {
+    name: "CtsShim",
+
+    sdk_version: "current",
+    optimize: {
+        enabled: false,
+    },
+    dex_preopt: {
+        enabled: false,
+    },
+
+    manifest: "shim/AndroidManifest.xml",
+}
diff --git a/packages/CtsShim/build/Android.mk b/packages/CtsShim/build/Android.mk
deleted file mode 100644
index 0ef4654..0000000
--- a/packages/CtsShim/build/Android.mk
+++ /dev/null
@@ -1,119 +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 := $(my-dir)
-
-###########################################################
-# Variant: Privileged app upgrade
-
-include $(CLEAR_VARS)
-# this needs to be a privileged application
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_SDK_VERSION := current
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PACKAGE_NAME := CtsShimPrivUpgrade
-
-LOCAL_MANIFEST_FILE := shim_priv_upgrade/AndroidManifest.xml
-
-LOCAL_MULTILIB := both
-LOCAL_JNI_SHARED_LIBRARIES := libshim_jni
-
-include $(BUILD_PACKAGE)
-my_shim_priv_upgrade_apk := $(LOCAL_BUILT_MODULE)
-
-###########################################################
-# Variant: Privileged app
-
-include $(CLEAR_VARS)
-# this needs to be a privileged application
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_SDK_VERSION := current
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PACKAGE_NAME := CtsShimPriv
-
-# Generate the upgrade key by taking the hash of the built CtsShimPrivUpgrade apk
-gen := $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),,true)/AndroidManifest.xml
-$(gen): PRIVATE_CUSTOM_TOOL = sed -e "s/__HASH__/`sha512sum $(PRIVATE_INPUT_APK) | cut -d' ' -f1`/" $< >$@
-$(gen): PRIVATE_INPUT_APK := $(my_shim_priv_upgrade_apk)
-$(gen): $(LOCAL_PATH)/shim_priv/AndroidManifest.xml $(my_shim_priv_upgrade_apk)
-	$(transform-generated-source)
-
-my_shim_priv_upgrade_apk :=
-
-LOCAL_FULL_MANIFEST_FILE := $(gen)
-
-LOCAL_MULTILIB := both
-LOCAL_JNI_SHARED_LIBRARIES := libshim_jni
-# Explicitly uncompress native libs rather than letting the build system doing it and destroy the
-# v2/v3 signature.
-LOCAL_USE_EMBEDDED_NATIVE_LIBS := true
-
-LOCAL_USE_AAPT2 := true
-
-include $(BUILD_PACKAGE)
-
-###########################################################
-# Variant: Privileged app upgrade w/ the wrong SHA
-
-include $(CLEAR_VARS)
-# this needs to be a privileged application
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_SDK_VERSION := current
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_DEX_PREOPT := false
-# anything to make this package's SHA different from CtsShimPrivUpgrade
-LOCAL_AAPT_FLAGS := --version-name WrongSHA
-
-LOCAL_PACKAGE_NAME := CtsShimPrivUpgradeWrongSHA
-
-LOCAL_MANIFEST_FILE := shim_priv_upgrade/AndroidManifest.xml
-
-LOCAL_MULTILIB := both
-LOCAL_JNI_SHARED_LIBRARIES := libshim_jni
-
-include $(BUILD_PACKAGE)
-
-
-###########################################################
-# Variant: System app
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_SDK_VERSION := current
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PACKAGE_NAME := CtsShim
-
-LOCAL_MANIFEST_FILE := shim/AndroidManifest.xml
-
-LOCAL_USE_AAPT2 := true
-
-include $(BUILD_PACKAGE)
-
-###########################################################
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
index cf286bd..738c425 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -99,11 +99,13 @@
             // init input stream before calling startInstallation(), which takes 90 seconds.
             initInputStream();
 
-            Thread thread = new Thread(() -> {
-                mInstallationSession =
-                        mDynSystem.startInstallation(mSystemSize, mUserdataSize);
-            });
-
+            Thread thread =
+                    new Thread(
+                            () -> {
+                                mDynSystem.startInstallation("userdata", mUserdataSize, false);
+                                mInstallationSession =
+                                        mDynSystem.startInstallation("system", mSystemSize, true);
+                            });
 
             thread.start();
 
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 48d34ae..af96982 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -129,17 +129,17 @@
     }
 
     @Override
-    protected int enforceReadPermissionInner(Uri uri, String callingPkg, IBinder callerToken)
-            throws SecurityException {
+    protected int enforceReadPermissionInner(Uri uri, String callingPkg,
+            @Nullable String featureId, IBinder callerToken) throws SecurityException {
         enforceShellRestrictions();
-        return super.enforceReadPermissionInner(uri, callingPkg, callerToken);
+        return super.enforceReadPermissionInner(uri, callingPkg, featureId, callerToken);
     }
 
     @Override
-    protected int enforceWritePermissionInner(Uri uri, String callingPkg, IBinder callerToken)
-            throws SecurityException {
+    protected int enforceWritePermissionInner(Uri uri, String callingPkg,
+            @Nullable String featureId, IBinder callerToken) throws SecurityException {
         enforceShellRestrictions();
-        return super.enforceWritePermissionInner(uri, callingPkg, callerToken);
+        return super.enforceWritePermissionInner(uri, callingPkg, featureId, callerToken);
     }
 
     public void updateVolumes() {
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
index 0a37cc6..99f6a92 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/handheld/UninstallAlertDialogFragment.java
@@ -16,7 +16,6 @@
 
 package com.android.packageinstaller.handheld;
 
-import static android.os.storage.StorageManager.convert;
 import static android.text.format.Formatter.formatFileSize;
 
 import android.annotation.NonNull;
@@ -34,8 +33,6 @@
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.os.storage.StorageManager;
-import android.os.storage.StorageVolume;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -64,29 +61,18 @@
      * @return The number of bytes.
      */
     private long getAppDataSizeForUser(@NonNull String pkg, @NonNull UserHandle user) {
-        StorageManager storageManager = getContext().getSystemService(StorageManager.class);
         StorageStatsManager storageStatsManager =
                 getContext().getSystemService(StorageStatsManager.class);
-
-        List<StorageVolume> volumes = storageManager.getStorageVolumes();
-        long appDataSize = 0;
-
-        int numVolumes = volumes.size();
-        for (int i = 0; i < numVolumes; i++) {
-            StorageStats stats;
-            try {
-                stats = storageStatsManager.queryStatsForPackage(convert(volumes.get(i).getUuid()),
-                        pkg, user);
-            } catch (PackageManager.NameNotFoundException | IOException e) {
-                Log.e(LOG_TAG, "Cannot determine amount of app data for " + pkg + " on "
-                        + volumes.get(i) + " (user " + user + ")", e);
-                continue;
-            }
-
-            appDataSize += stats.getDataBytes();
+        try {
+            StorageStats stats = storageStatsManager.queryStatsForPackage(
+                    getContext().getPackageManager().getApplicationInfo(pkg, 0).storageUuid,
+                    pkg, user);
+            return stats.getDataBytes();
+        } catch (PackageManager.NameNotFoundException | IOException e) {
+            Log.e(LOG_TAG, "Cannot determine amount of app data for " + pkg, e);
         }
 
-        return appDataSize;
+        return 0;
     }
 
     /**
diff --git a/packages/PrintSpooler/res/values-mr/strings.xml b/packages/PrintSpooler/res/values-mr/strings.xml
index 10dec8e..44456b4 100644
--- a/packages/PrintSpooler/res/values-mr/strings.xml
+++ b/packages/PrintSpooler/res/values-mr/strings.xml
@@ -87,7 +87,7 @@
     <string name="restart" msgid="2472034227037808749">"रीस्टार्ट करा"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"प्रिंटरवर कोणतेही कनेक्‍शन नाही"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"अज्ञात"</string>
-    <string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> वापरायची?"</string>
+    <string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> वापरायचे?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"तुमचा दस्तऐवज प्रिंटरपर्यंत पोहचण्‍यापूर्वी एक किंवा अधिक सर्व्हरद्वारे जाऊ शकतो."</string>
   <string-array name="color_mode_labels">
     <item msgid="7602948745415174937">"कृष्‍ण धवल"</item>
diff --git a/packages/PrintSpooler/res/values-my/strings.xml b/packages/PrintSpooler/res/values-my/strings.xml
index fdcdd7c..a6b07e1 100644
--- a/packages/PrintSpooler/res/values-my/strings.xml
+++ b/packages/PrintSpooler/res/values-my/strings.xml
@@ -87,7 +87,7 @@
     <string name="restart" msgid="2472034227037808749">"ပြန်စရန်"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"စာထုတ်စက်နဲ့ ဆက်သွယ်ထားမှု မရှိပါ"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"မသိ"</string>
-    <string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g>ကိုသုံးမလား။"</string>
+    <string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> ကိုသုံးမလား။"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"သင်၏ စာရွက်စာတမ်းများသည် ပရင်တာထံသို့ သွားစဉ် ဆာဗာ တစ်ခု သို့မဟုတ် ပိုများပြီး ဖြတ်ကျော်နိုင်ရသည်။"</string>
   <string-array name="color_mode_labels">
     <item msgid="7602948745415174937">"အဖြူ အမည်း"</item>
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
index c4df2e8..b9daf7f 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
@@ -406,8 +406,8 @@
             return null;
         }
         try {
-            return provider.call(context.getPackageName(), uri.getAuthority(),
-                    method, uri.toString(), bundle);
+            return provider.call(context.getPackageName(), context.getFeatureId(),
+                    uri.getAuthority(), method, uri.toString(), bundle);
         } catch (RemoteException e) {
             return null;
         }
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 245ca14..843967d 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Beskikbaar via %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Tik om aan te meld"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Gekoppel, geen internet nie"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Daar kan nie by private DNS-bediener ingegaan word nie"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Beperkte verbinding"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Geen internet nie"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Aanmelding word vereis"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Middelmatig"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Vinnig"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Baie vinnig"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Ontkoppel"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Ontkoppel tans…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Totdat jy dit afskakel"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Sopas"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Hierdie toestel"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index bfd3196..871a7fc 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"በ%1$s በኩል የሚገኝ"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"ለመመዝገብ መታ ያድርጉ"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ተገናኝቷል፣ ምንም በይነመረብ የለም"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"የግል ዲኤንኤስ አገልጋይ ሊደረስበት አይችልም"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"የተገደበ ግንኙነት"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ምንም በይነመረብ የለም"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ወደ መለያ መግባት ያስፈልጋል"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"መካከለኛ"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"ፈጣን"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"እጅግ በጣም ፈጣን"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"ተለያይቷል"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"በመለያየት ላይ..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"እስኪያጠፉት ድረስ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ልክ አሁን"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"ይህ መሣሪያ"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 8b67b0b..9ee6322 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"‏متوفرة عبر %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"انقر للاشتراك."</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"متصلة ولكن بلا إنترنت"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"لا يمكن الوصول إلى خادم أسماء نظام نطاقات خاص"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"اتصال محدود"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"لا يتوفر اتصال إنترنت."</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"يلزم تسجيل الدخول"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"متوسطة"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"سريعة"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"سريعة جدًا"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"غير متصل"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"جارٍ قطع الاتصال..."</string>
@@ -469,4 +472,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"إلى أن توقف الوضع يدويًا"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"للتو"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"هذا الجهاز"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index f3ca337..9dcd8ba 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$sৰ মাধ্যমেৰে উপলব্ধ"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"ছাইন আপ কৰিবলৈ টিপক"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"সংযোজিত, ইণ্টাৰনেট নাই"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"ব্যক্তিগত DNS ছাৰ্ভাৰ এক্সেছ কৰিব নোৱাৰি"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"ইণ্টাৰনেট সংযোগ সীমিত"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ইণ্টাৰনেট সংযোগ নাই"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ছাইন ইন কৰা দৰকাৰী"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"মধ্যমীয়া"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"দ্ৰুত"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"অতি দ্ৰুত"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"সংযোগ বিচ্ছিন্ন কৰা হ’ল"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"সংযোগ বিচ্ছিন্ন কৰি থকা হৈছে…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"আপুনি অফ নকৰা পর্যন্ত"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"এই মাত্ৰ"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"এই ডিভাইচটো"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index d35dfe8..fda96b4 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s vasitəsilə əlçatandır"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Qeydiyyatdan keçmək üçün klikləyin"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Qoşuludur, internet yoxdur"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Özəl DNS serverinə giriş mümkün deyil"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Məhdud bağlantı"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"İnternet yoxdur"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Giriş tələb olunur"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Orta"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Sürətli"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Çox Sürətli"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Ayrıldı"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Ayrılır..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Deaktiv edənə qədər"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"İndicə"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Bu cihaz"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 448de4b..4dfbd8e 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Dostupna je preko pristupne tačke %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Dodirnite da biste se registrovali"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Veza je uspostavljena, nema interneta"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Pristup privatnom DNS serveru nije uspeo"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Ograničena veza"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Nema interneta"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Treba da se prijavite"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Srednja"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Brza"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Veoma brza"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Veza je prekinuta"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Prekidanje veze..."</string>
@@ -466,4 +469,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dok ne isključite"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Upravo"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Ovaj uređaj"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index d68c0f3..577c1eb 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Даступна праз %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Націсніце, каб зарэгістравацца"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Падключана, без доступу да інтэрнэту"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Не ўдалося атрымаць доступ да прыватнага DNS-сервера"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Абмежаваныя магчымасці падключэння"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Не падключана да інтэрнэту"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Трэба выканаць уваход"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Сярэдняя"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Хуткая"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Вельмі хуткая"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Адключана"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Адключэнне..."</string>
@@ -467,4 +470,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Пакуль не выключыце"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Толькі што"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Гэта прылада"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index cb99f64..1007b38 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Мрежата е достъпна през „%1$s“"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Докоснете, за да се регистрирате"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Установена е връзка – няма достъп до интернет"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Не може да се осъществи достъп до частния DNS сървър"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Ограничена връзка"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Няма връзка с интернет"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Изисква се вход в профила"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Средна"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Бърза"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Много бърза"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Изкл."</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Изключва се..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"До изключване"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Току-що"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Това устройство"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index f2f4f52..a92e8e4 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s এর মাধ্যমে উপলব্ধ"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"সাইন-আপ করতে ট্যাপ করুন"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"কানেক্ট, ইন্টারনেট নেই"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"ব্যক্তিগত ডিএনএস সার্ভার অ্যাক্সেস করা যাবে না"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"সীমিত কানেকশন"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ইন্টারনেট কানেকশন নেই"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"সাইন-ইন করা দরকার"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"মাঝারি"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"দ্রুত"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"খুব দ্রুত"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"ডিসকানেক্ট করা হয়েছে"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"ডিসকানেক্ট হচ্ছে..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"যতক্ষণ না আপনি বন্ধ করছেন"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"এখনই"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"এই ডিভাইস"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 45b8dd9..af7219d 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Dostupan preko %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Dodirnite za prijavu"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Povezano, nema interneta"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Nije moguće pristupiti privatnom DNS serveru"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Ograničena veza"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Nema internetske veze"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Potrebna je prijava"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Srednja brzina"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Brzo"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Veoma brzo"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Isključen"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Prekidanje veze…"</string>
@@ -466,4 +469,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dok ne isključite"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Upravo"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Ovaj uređaj"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index b624df0..ad6a131 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponible mitjançant %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Toca per registrar-te"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connectada, sense Internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"No es pot accedir al servidor DNS privat"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Connexió limitada"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Sense connexió a Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Cal iniciar la sessió"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Mitjana"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Ràpida"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Molt ràpida"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Desconnectat"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"S\'està desconnectant..."</string>
@@ -237,7 +240,7 @@
     <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="7234956835280563341">"Activa el còdec d\'àudio per Bluetooth\nSelecció: mode de canal"</string>
     <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Còdec LDAC d\'àudio per Bluetooth: qualitat de reproducció"</string>
     <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="6893955536658137179">"Activa l\'LDAC d\'àudio per Bluetooth\nSelecció de còdec: qualitat de reproducció"</string>
-    <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"S\'està reproduint en temps real: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
+    <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Reproducció en continu: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
     <string name="select_private_dns_configuration_title" msgid="3700456559305263922">"DNS privat"</string>
     <string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Selecciona el mode de DNS privat"</string>
     <string name="private_dns_mode_off" msgid="8236575187318721684">"Desactivat"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Fins que no ho desactivis"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Ara mateix"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Aquest dispositiu"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 042e12a..577200c 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Dostupné prostřednictvím %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Klepnutím se zaregistrujete"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Připojeno, není k dispozici internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Nelze získat přístup k soukromému serveru DNS"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Omezené připojení"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Nejste připojeni k internetu"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Je vyžadováno přihlášení"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Střední"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Rychlá"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Velmi rychlá"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Odpojeno"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Odpojování..."</string>
@@ -467,4 +470,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dokud tuto funkci nevypnete"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Právě teď"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Toto zařízení"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 4723293..43bd1f15 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Tilgængelig via %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Tryk for at registrere dig"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Tilsluttet – intet internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Der er ikke adgang til den private DNS-server"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Begrænset forbindelse"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Intet internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Login er påkrævet"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Middel"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Hurtig"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Meget hurtig"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> – <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Afbrudt"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Afbryder ..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Indtil du deaktiverer"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Lige nu"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Denne enhed"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 4f5a965..8f6d123 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Verfügbar über %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Zum Anmelden tippen"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Verbunden, kein Internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Auf den privaten DNS-Server kann nicht zugegriffen werden"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Eingeschränkte Verbindung"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Kein Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Anmeldung erforderlich"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Mittel"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Schnell"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Sehr schnell"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> – <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Nicht verbunden"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Verbindung wird getrennt..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Bis zur Deaktivierung"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"gerade eben"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Dieses Gerät"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 753dea8..fcdc410 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Διαθέσιμο μέσω %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Πατήστε για εγγραφή"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Συνδέθηκε, χωρίς σύνδεση στο διαδίκτυο"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Δεν είναι δυνατή η πρόσβαση στον ιδιωτικό διακομιστή DNS."</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Περιορισμένη σύνδεση"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Δεν υπάρχει σύνδεση στο διαδίκτυο"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Απαιτείται σύνδεση"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Μέτρια"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Γρήγορη"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Πολύ γρήγορη"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Αποσυνδέθηκε"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Αποσύνδεση..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Μέχρι την απενεργοποίηση"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Μόλις τώρα"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Αυτή η συσκευή"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index dd3d278..65b19ee 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Available via %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Tap to sign up"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connected, no Internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Private DNS server cannot be accessed"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Limited connection"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"No Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Sign-in required"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Medium"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Fast"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Very fast"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Disconnected"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Disconnecting…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"This device"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index dd3d278..65b19ee 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Available via %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Tap to sign up"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connected, no Internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Private DNS server cannot be accessed"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Limited connection"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"No Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Sign-in required"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Medium"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Fast"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Very fast"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Disconnected"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Disconnecting…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"This device"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index dd3d278..65b19ee 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Available via %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Tap to sign up"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connected, no Internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Private DNS server cannot be accessed"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Limited connection"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"No Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Sign-in required"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Medium"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Fast"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Very fast"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Disconnected"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Disconnecting…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"This device"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index dd3d278..65b19ee 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Available via %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Tap to sign up"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connected, no Internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Private DNS server cannot be accessed"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Limited connection"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"No Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Sign-in required"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Medium"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Fast"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Very fast"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Disconnected"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Disconnecting…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Until you turn off"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Just now"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"This device"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index d9f61d8..3843085 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‏‎‎‏‏‏‎‎‏‎‎‏‎‎‏‏‎‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‏‏‎‎‎‎‏‏‎‏‎Available via %1$s‎‏‎‎‏‎"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‎‎‏‎‎‎‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‏‎‎Tap to sign up‎‏‎‎‏‎"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‎‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‎‎‎‏‎‎‎‏‏‎‏‎‎‏‎‏‎Connected, no internet‎‏‎‎‏‎"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‏‎‎‏‏‎‎‏‎‏‏‎‎‎‎‎‎‏‎‏‏‎‏‎‎‎‎‏‎‏‎‎Private DNS server cannot be accessed‎‏‎‎‏‎"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‎‎‎‏‎‎‎‎‏‎‏‎‎‏‏‎‎‎‎‎‏‏‎‏‎‎‎‏‎‏‏‏‎‏‏‏‎Limited connection‎‏‎‎‏‎"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‏‏‏‎‏‏‎‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‏‎‏‎‏‎‎‏‎No internet‎‏‎‎‏‎"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‎‏‏‏‎‏‏‎‏‏‎‏‏‎‏‎‎‏‎‎‎‏‏‏‎‎‎‏‎‎‏‏‏‎‏‏‎‏‎‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‏‎‏‎‎‎Sign in required‎‏‎‎‏‎"</string>
@@ -60,6 +61,7 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‎‎‎‎‎‏‎‎‏‎‏‎‎‏‎‎‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‎‏‎‎‎‎‏‏‏‎‎‏‏‏‎‎‏‎‎‏‎‎‎‎‎‎‏‎Medium‎‏‎‎‏‎"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‎‎‏‏‏‏‎‎‏‎‎‏‏‎‎‎‎‏‏‎‎‎‎‎‎‏‎‎‎‏‎‏‎‎‎‎‎‏‏‏‏‎‎‏‎‏‎‏‎‎‎‏‎Fast‎‏‎‎‏‎"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‏‏‎‎‎‎‎‎‎‎‏‎‎‏‏‎‏‏‎‎‏‏‎‎‎‏‎‎‏‎‎‏‎‏‏‏‎‎‏‎‎‏‎‎‎‏‎Very Fast‎‏‎‎‏‎"</string>
+    <string name="wifi_passpoint_expired" msgid="1711402866023391443">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‎‎‎‎‎‎‎‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎Expired‎‏‎‎‏‎"</string>
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‏‏‎‎‏‎‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‎‏‎‎‎‎‎‏‎‎‏‎‎‏‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="STATE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ / ‎‏‎‎‏‏‎<xliff:g id="DESCRIPTION">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‏‏‏‏‎‏‎‎‎‎‎‏‎‏‎‏‏‏‎‏‏‎‏‏‏‎‏‏‎‎‎‎‏‏‏‎‏‏‏‎Disconnected‎‏‎‎‏‎"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‏‏‏‎‎‎‏‎‎‏‏‎‎‏‎‎‎‏‎‎‏‏‏‎‏‏‎‎‏‎‏‏‎‎‎‏‏‏‎‏‏‏‎‎Disconnecting…‎‏‎‎‏‎"</string>
@@ -465,4 +467,5 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‎‎‏‏‏‏‎‎‏‏‏‏‏‎‎‎‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‏‏‎‏‎‏‏‎‎‎‎‏‏‎‎‎‎‎‎‏‏‏‎Until you turn off‎‏‎‎‏‎"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‏‏‎‎‎‏‏‎‏‎‏‎‏‎‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‎‏‏‎‎Just now‎‏‎‎‏‎"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‏‎‏‎‏‏‎‏‎‏‎‎‏‏‏‎‎‏‎‎‏‎‏‎‏‏‎‏‏‎‏‎‏‏‎‎‎‏‏‏‏‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‎‏‎This device‎‏‎‎‏‎"</string>
+    <string name="profile_connect_timeout_subtext" msgid="2401801610868184557">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‎‏‎‎‏‏‏‎‏‎‎‏‏‏‎‏‎‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‎‏‎‏‎‏‎‏‏‏‏‎‏‏‎‏‎Problem connecting. Turn device off &amp; back on‎‏‎‎‏‎"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 30cb0a1..2e1a132 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponible a través de %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Presiona para registrarte"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Conectado pero sin conexión a Internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"No se puede acceder al servidor DNS privado"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Conexión limitada"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Sin Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Acceso obligatorio"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Media"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Rápida"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Muy rápida"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Desconectado"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Desconectando…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Hasta que lo desactives"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Recién"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Este dispositivo"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 32905df..31ac2a1 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponible a través de %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Toca para registrarte"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Conexión sin Internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"No se ha podido acceder al servidor DNS privado"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Conexión limitada"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Sin Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Debes iniciar sesión"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Media"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Rápida"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Muy rápida"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Desconectado"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Desconectando…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Hasta que se desactive"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Justo ahora"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Este dispositivo"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 79b8a84..983132a 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Saadaval üksuse %1$s kaudu"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Puudutage registreerumiseks"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Ühendatud, Interneti-ühendus puudub"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Privaatsele DNS-serverile ei pääse juurde"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Piiratud ühendus"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Interneti-ühendus puudub"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Nõutav on sisselogimine"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Keskmine"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Kiire"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Väga kiire"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Ühendus katkestatud"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Ühenduse katkestamine ..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Kuni välja lülitate"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Äsja"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"See seade"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 38ae9c2..727c656 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s bidez erabilgarri"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Sakatu erregistratzeko"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Konektatuta; ezin da atzitu Internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Ezin da atzitu DNS zerbitzari pribatua"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Konexio mugatua"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Ez dago Interneteko konexiorik"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Saioa hasi behar da"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Tartekoa"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Bizkorra"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Oso bizkorra"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Deskonektatuta"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Deskonektatzen…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Zuk desaktibatu arte"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Oraintxe"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Gailu hau"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index a883d6cd..f93af2a 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"‏در دسترس از طریق %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"برای ثبت‌نام ضربه بزنید"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"متصل، بدون اینترنت"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"‏سرور DNS خصوصی قابل دسترسی نیست"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"اتصال محدود"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"عدم دسترسی به اینترنت"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ورود به سیستم لازم است"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"متوسط"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"سریع"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"خیلی سریع"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"اتصال قطع شد"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"در حال قطع اتصال..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"تا زمانی‌که آن را خاموش کنید"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"هم‌اکنون"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"این دستگاه"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 929e101..8550826 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Käytettävissä seuraavan kautta: %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Rekisteröidy napauttamalla"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Yhdistetty, ei internetyhteyttä"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Ei pääsyä yksityiselle DNS-palvelimelle"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Rajallinen yhteys"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Ei internetyhteyttä"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Sisäänkirjautuminen vaaditaan"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Kohtuullinen"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Nopea"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Hyvin nopea"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Yhteys katkaistu"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Katkaistaan yhteyttä..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Kunnes poistat sen käytöstä"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Äsken"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Tämä laite"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index d3bfc96..5c84be7 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Accessible par %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Toucher pour vous connecter"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connecté, aucun accès à Internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Impossible d\'accéder au serveur DNS privé"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Connexion limitée"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Aucune connexion Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Connexion requise"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Moyenne"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Élevée"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Très rapide"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> : <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Déconnecté"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Déconnexion…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Jusqu\'à la désactivation"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"À l\'instant"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Cet appareil"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index b5706ce..a6711c7 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponible via %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Appuyez ici pour vous connecter"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connecté, aucun accès à Internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Impossible d\'accéder au serveur DNS privé"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Connexion limitée"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Aucun accès à Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Connexion requise"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Moyenne"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Élevée"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Très élevée"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Déconnecté"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Déconnexion…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Jusqu\'à la désactivation"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"À l\'instant"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Cet appareil"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 2aa1604..c70c453 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Dispoñible a través de %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Toca para rexistrarte"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Conexión sen Internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Non se puido acceder ao servidor DNS privado"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Pouca conexión"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Non hai conexión a Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"É obrigatorio iniciar sesión"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Media"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Rápida"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Moi rápida"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Desconectado"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Desconectando..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Ata a desactivación"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Agora mesmo"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Este dispositivo"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index c2cc4c5..34a8355a 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s દ્વારા ઉપલબ્ધ"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"સાઇન અપ કરવા માટે ટૅપ કરો"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"કનેક્ટ કર્યું, કોઈ ઇન્ટરનેટ નથી"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"ખાનગી DNS સર્વર ઍક્સેસ કરી શકાતા નથી"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"મર્યાદિત કનેક્શન"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ઇન્ટરનેટ ઍક્સેસ નથી"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"સાઇન ઇન આવશ્યક"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"મધ્યમ"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"ઝડપી"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"ખૂબ ઝડપી"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"ડિસ્કનેક્ટ કર્યું"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"ડિસ્કનેક્ટ થઈ રહ્યું છે..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"તમે બંધ ન કરો ત્યાં સુધી"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"હમણાં જ"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"આ ડિવાઇસ"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 66c7a16..758ce27 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s के द्वारा उपलब्ध"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"साइन अप करने के लिए टैप करें"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"कनेक्ट हो गया है, लेकिन इंटरनेट नहीं है"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"निजी डीएनएस सर्वर को ऐक्सेस नहीं किया जा सकता"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"सीमित कनेक्शन"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"इंटरनेट कनेक्शन नहीं है"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"साइन इन करना ज़रूरी है"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"मध्यम"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"तेज़"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"अत्‍यधिक तेज़"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"डिसकनेक्ट किया गया"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"डिस्‍कनेक्‍ट हो रहा है..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"जब तक आप इसे बंद नहीं करते"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"अभी-अभी"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"यह डिवाइस"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 0fc16f8..2f89a66 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Dostupno putem %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Dodirnite da biste se registrirali"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Povezano, bez interneta"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Nije moguće pristupiti privatnom DNS poslužitelju"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Ograničena veza"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Nema interneta"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Obavezna prijava"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Srednje"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Brzo"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Vrlo brzo"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Niste povezani"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Isključivanje…"</string>
@@ -466,4 +469,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dok ne isključite"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Upravo sad"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Ovaj uređaj"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 1388dbb..8f6e776 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Elérhető a következőn keresztül: %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Koppintson a regisztrációhoz"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Csatlakozva, nincs internet-hozzáférés"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"A privát DNS-kiszolgálóhoz nem lehet hozzáférni"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Korlátozott kapcsolat"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Nincs internetkapcsolat"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Bejelentkezést igényel"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Közepes"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Gyors"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Nagyon gyors"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Szétkapcsolva"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Szétkapcsolás..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Kikapcsolásig"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Az imént"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Ez az eszköz"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 2145adb..3791b94 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Հասանելի է %1$s-ի միջոցով"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Հպեք՝ գրանցվելու համար"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Միացված է, սակայն ինտերնետ կապ չկա"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Մասնավոր DNS սերվերն անհասանելի է"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Սահմանափակ կապ"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Ինտերնետ կապ չկա"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Անհրաժեշտ է մուտք գործել"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Միջին"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Արագ"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Շատ արագ"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Անջատված է"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Անջատվում է..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Մինչև չանջատեք"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Հենց նոր"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Այս սարքը"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 7ebe6b7..1a82484 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Tersedia melalui %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Ketuk untuk mendaftar"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Tersambung, tidak ada internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Server DNS pribadi tidak dapat diakses"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Koneksi terbatas"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Tidak ada internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Perlu login"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Sedang"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Cepat"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Sangat Cepat"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Sambungan terputus"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Memutus sambungan..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Sampai Anda menonaktifkannya"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Baru saja"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Perangkat ini"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index eede117..c75e12b 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Í boði í gegnum %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Ýttu til að skrá þig"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Tengt, enginn netaðgangur"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Ekki næst í DNS-einkaþjón"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Takmörkuð tenging"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Engin nettenging"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Innskráningar krafist"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Miðlungshratt"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Hratt"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Mjög hratt"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Aftengt"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Aftengist…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Þar til þú slekkur"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Rétt í þessu"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Þetta tæki"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 2c64ec2..b00d06d 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponibile tramite %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Tocca per registrarti"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Connesso, senza Internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Non è possibile accedere al server DNS privato"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Connessione limitata"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Nessuna connessione a Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Accesso richiesto"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Media"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Veloce"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Molto veloce"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Disconnesso"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Disconnessione..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Fino alla disattivazione"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Adesso"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Questo dispositivo"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 30d6a4a..8aeb9af 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"‏זמינה דרך %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"יש להקיש כדי להירשם"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"מחובר. אין אינטרנט"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"‏לא ניתן לגשת לשרת DNS הפרטי"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"חיבור מוגבל"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"אין אינטרנט"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"נדרשת כניסה"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"בינונית"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"מהירה"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"מהירה מאוד"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"מנותק"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"מתנתק..."</string>
@@ -467,4 +470,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"עד הכיבוי"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"הרגע"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"המכשיר הזה"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 6cb5514..bd17074 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s経由で使用可能"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"タップして登録してください"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"接続済み、インターネット接続なし"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"プライベート DNS サーバーにアクセスできません"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"接続が制限されています"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"インターネット未接続"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ログインが必要"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"普通"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"速い"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"非常に速い"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"切断"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"切断中..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"OFF にするまで"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"たった今"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"このデバイス"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 4c78a38..b1fa87f 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"ხელმისაწვდომია %1$s-ით"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"შეეხეთ რეგისტრაციისთვის"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"დაკავშირებულია, ინტერნეტის გარეშე"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"პირად DNS სერვერზე წვდომა შეუძლებელია"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"შეზღუდული კავშირი"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ინტერნეტ-კავშირი არ არის"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"აუცილებელია სისტემაში შესვლა"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"საშუალო"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"სწრაფი"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"ძალიან სწრაფი"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"კავშირი გაწყვეტილია"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"მიმდინარეობს გათიშვა…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"გამორთვამდე"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ახლახან"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"ეს მოწყობილობა"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index ce08657..e4dc6ef 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s арқылы қолжетімді"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Тіркелу үшін түртіңіз."</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Қосылған, интернет жоқ"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Жеке DNS серверіне кіру мүмкін емес."</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Шектеулі байланыс"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Интернетпен байланыс жоқ"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Есептік жазбаға кіру керек"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Орташа"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Жылдам"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Өте жылдам"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Ажыратылған"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Ажыратылуда…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Өшірілгенге дейін"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Дәл қазір"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Осы құрылғы"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 43c9282..5ca7fe7 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"មានតាមរយៈ %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"ចុច​ដើម្បី​ចុះឈ្មោះ"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"បាន​ភ្ជាប់ ប៉ុន្តែ​គ្មាន​អ៊ីនធឺណិត​ទេ"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"មិនអាច​ចូលប្រើ​ម៉ាស៊ីនមេ DNS ឯកជន​បានទេ"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"ការតភ្ជាប់មានកម្រិត"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"គ្មាន​អ៊ីនធឺណិតទេ"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"តម្រូវ​ឱ្យ​ចូល​គណនី"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"មធ្យម"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"លឿន"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"លឿន​ណាស់"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"បាន​ផ្ដាច់"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"កំពុង​ផ្ដាច់…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"រហូតទាល់តែ​អ្នកបិទ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"អម្បាញ់មិញ"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"ឧបករណ៍នេះ"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 253104b..cbdb62c 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s ಮೂಲಕ ಲಭ್ಯವಿದೆ"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"ಸೈನ್ ಅಪ್ ಮಾಡಲು ಟ್ಯಾಪ್‌ ಮಾಡಿ"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ, ಇಂಟರ್ನೆಟ್ ಇಲ್ಲ"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"ಖಾಸಗಿ DNS ಸರ್ವರ್ ಅನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"ಸೀಮಿತ ಸಂಪರ್ಕ"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ಇಂಟರ್ನೆಟ್ ಇಲ್ಲ"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ಸೈನ್ ಇನ್ ಮಾಡುವ ಅಗತ್ಯವಿದೆ"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"ಮಧ್ಯಮ"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"ವೇಗ"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"ತುಂಬಾ ವೇಗವಾಗಿದೆ"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗುತ್ತಿದೆ..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"ನೀವು ಆಫ್ ಮಾಡುವವರೆಗೆ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ಇದೀಗ"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"ಈ ಸಾಧನ"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index ac44c0d..9d4a947 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s을(를) 통해 사용 가능"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"탭하여 가입"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"연결됨, 인터넷 사용 불가"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"비공개 DNS 서버에 액세스할 수 없습니다."</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"제한된 연결"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"인터넷 연결 없음"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"로그인 필요"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"보통"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"빠름"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"매우 빠름"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"연결 끊김"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"연결을 끊는 중…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"사용 중지할 때까지"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"조금 전"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"이 기기"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index dd1ff30..46e002f 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s аркылуу жеткиликтүү"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Катталуу үчүн таптап коюңуз"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Туташып турат, Интернет жок"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Жеке DNS сервери жеткиликсиз"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Байланыш чектелген"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Интернет жок"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Аккаунтка кирүү талап кылынат"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Орто"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Ылдам"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Абдан ылдам"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Ажыратылган"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Ажыратылууда…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Бул функция өчүрүлгөнгө чейин"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Азыр эле"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Ушул түзмөк"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 28e8111..981685e 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"ມີ​ໃຫ້​ຜ່ານ %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"ແຕະເພື່ອສະໝັກ"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ເຊື່ອມຕໍ່ແລ້ວ, ບໍ່ມີອິນເຕີເນັດ"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"ບໍ່ສາມາດເຂົ້າເຖິງເຊີບເວີ DNS ສ່ວນຕົວໄດ້"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"ການເຊື່ອມຕໍ່ຈຳກັດ"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ບໍ່ມີອິນເຕີເນັດ"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ຈຳເປັນຕ້ອງເຂົ້າສູ່ລະບົບ"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"ປານກາງ"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"ໄວ"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"ໄວຫຼາຍ"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"ຕັດການເຊື່ອມຕໍ່ແລ້ວ"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"ກຳລັງຢຸດການເຊື່ອມຕໍ່..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"ຈົນກວ່າທ່ານຈະປິດ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ຕອນນີ້"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"ອຸປະກອນນີ້"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 93fcaa7..6d23090 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Pasiekiama naudojant „%1$s“"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Palieskite, kad prisiregistruotumėte"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Prisijungta, nėra interneto"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Privataus DNS serverio negalima pasiekti"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Ribotas ryšys"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Nėra interneto ryšio"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Reikia prisijungti"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Vidutinis"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Greitas"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Labai greitas"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Atsijungęs (-usi)"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Atjungiama..."</string>
@@ -467,4 +470,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Kol išjungsite"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Ką tik"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Šis įrenginys"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index c12d097..76304e0 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Pieejams, izmantojot %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Pieskarieties, lai reģistrētos"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Savienojums izveidots, nav piekļuves internetam"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Nevar piekļūt privātam DNS serverim."</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Ierobežots savienojums"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Nav piekļuves internetam"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Nepieciešama pierakstīšanās"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Vidējs"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Ātrs"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Ļoti ātrs"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Atvienots"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Notiek atvienošana..."</string>
@@ -466,4 +469,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Līdz brīdim, kad izslēgsiet"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Tikko"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Šī ierīce"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 9a76a0a..d0a284a 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Достапно преку %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Допрете за да се регистрирате"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Поврзана, нема интернет"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Не може да се пристапи до приватниот DNS-сервер"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Ограничена врска"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Нема интернет"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Потребно е најавување"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Средна"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Брза"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Многу брза"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Исклучено"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Се исклучува..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Додека не го исклучите"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Неодамнешни"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Овој уред"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index bb76295..b5649aa 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s വഴി ലഭ്യം"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"സൈൻ അപ്പ് ചെയ്യാൻ ടാപ്പ് ചെയ്യുക"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"കണക്റ്റ് ചെയ്‌തു, ഇന്റർനെറ്റ് ഇല്ല"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"സ്വകാര്യ DNS സെർവർ ആക്‌സസ് ചെയ്യാനാവില്ല"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"പരിമിത കണക്‌ഷൻ"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ഇന്റർനെറ്റ് ഇല്ല"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"സൈൻ ഇൻ ചെയ്യേണ്ടത് ആവശ്യമാണ്"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"ഇടത്തരം"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"വേഗത്തിൽ"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"വളരെ വേഗത്തിൽ"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"വിച്ഛേദിച്ചു"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"വിച്‌ഛേദിക്കുന്നു..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"നിങ്ങൾ ഓഫാക്കുന്നത് വരെ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ഇപ്പോൾ"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"ഈ ഉപകരണം"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 65a8ca6..9391142 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s-р боломжтой"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Бүртгүүлэхийн тулд товшино уу"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Холбогдсон хэдий ч интернет алга"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Хувийн DNS серверт хандах боломжгүй байна"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Хязгаарлагдмал холболт"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Интернэт алга"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Нэвтрэх шаардлагатай"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Дунд"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Хурдан"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Маш хурдан"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Салгагдсан"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Салгаж байна…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Таныг унтраах хүртэл"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Дөнгөж сая"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Энэ төхөөрөмж"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 3d75ad6..224aa11 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s द्वारे उपलब्‍ध"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"साइन अप करण्यासाठी टॅप करा"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"कनेक्‍ट केले, इंटरनेट नाही"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"खाजगी DNS सर्व्हर अॅक्सेस करू शकत नाही"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"मर्यादित कनेक्शन"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"इंटरनेट नाही"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"साइन इन करणे आवश्यक आहे"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"मध्‍यम"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"जलद"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"खूप जलद"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"डिस्कनेक्ट केले"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"डिस्कनेक्ट करत आहे..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"तुम्ही बंद करेपर्यंत"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"आत्ताच"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"हे डिव्हाइस"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 0b2a4b0..1c88ba3 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Tersedia melalui %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Ketik untuk daftar"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Disambungkan, tiada Internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Pelayan DNS peribadi tidak boleh diakses"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Sambungan terhad"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Tiada Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Log masuk diperlukan"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Sederhana"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Laju"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Sangat Laju"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Diputuskan sambungan"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Memutuskan sambungan..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Sehingga anda matikan"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Sebentar tadi"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Peranti ini"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 6fde69a..d6a2b93 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s မှတစ်ဆင့်ရနိုင်သည်"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"အကောင့်ဖွင့်ရန် တို့ပါ"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ချိတ်ဆက်ထားသည်၊ အင်တာနက်မရှိ"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"သီးသန့် ဒီအန်အက်စ် (DNS) ဆာဗာကို သုံး၍မရပါ။"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"ချိတ်ဆက်မှု ကန့်သတ်ထားသည်"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"အင်တာနက် မရှိပါ"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"လက်မှတ်ထိုးဝင်ရန် လိုအပ်သည်"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"အတော်အသင့်"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"မြန်"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"အလွန်မြန်"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"ချိတ်ဆက်မှုပြတ်တောက်သည်"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"အဆက်အသွယ်ဖြတ်တောက်သည်"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"သင်ပိတ်လိုက်သည် အထိ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ယခုလေးတင်"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"ဤစက်ပစ္စည်း"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 66ad20e..51d84a0 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Tilgjengelig via %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Trykk for å registrere deg"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Tilkoblet – ingen Internett-tilgang"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Den private DNS-tjeneren kan ikke nås"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Begrenset tilkobling"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Ingen internettilkobling"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Pålogging kreves"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Middels"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Rask"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Veldig rask"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Frakoblet"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Kobler fra…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Til du slår av"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Nå nettopp"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Denne enheten"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 860e9bf..b41b0c7 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s मार्फत उपलब्ध"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"साइन अप गर्न ट्याप गर्नुहोस्"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"जडान गरियो तर इन्टरनेट छैन"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"निजी DNS सर्भरमाथि पहुँच प्राप्त गर्न सकिँदैन"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"सीमित जडान"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"इन्टरनेटमाथिको पहुँच छैन"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"साइन इन गर्न आवश्यक छ"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"मध्यम"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"छिटो"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"धेरै छिटो"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"विच्छेदन गरियो"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"जडान हटाइँदै ..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"तपाईंले निष्क्रिय नपार्दासम्म"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"अहिले भर्खरै"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"यो यन्त्र"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 2fff3283..70d652d 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Beschikbaar via %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Tik om aan te melden"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Verbonden, geen internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Geen toegang tot privé-DNS-server"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Beperkte verbinding"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Geen internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Inloggen vereist"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Gemiddeld"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Snel"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Zeer snel"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Verbinding verbroken"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Verbinding verbreken..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Totdat je uitschakelt"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Zojuist"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Dit apparaat"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index ff2a534..c4e0e300 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s ମାଧ୍ୟମରେ ଉପଲବ୍ଧ"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"ସାଇନ୍ ଅପ୍ ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ସଂଯୁକ୍ତ, ଇଣ୍ଟର୍‌ନେଟ୍‌ ନାହିଁ"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"ବ୍ୟକ୍ତିଗତ DNS ସର୍ଭର୍ ଆକ୍ସେସ୍ କରିହେବ ନାହିଁ"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"ସୀମିତ ସଂଯୋଗ"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"କୌଣସି ଇଣ୍ଟରନେଟ୍‌ ନାହିଁ"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ସାଇନ୍-ଇନ୍ ଆବଶ୍ୟକ"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"ମଧ୍ୟମ"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"ଦ୍ରୁତ"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"ଅତି ଦ୍ରୁତ"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"ବିଛିନ୍ନ ହେଲା"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"ବିଚ୍ଛିନ୍ନ କରୁଛି…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"ଆପଣ ବନ୍ଦ ନକରିବା ପର୍ଯ୍ୟନ୍ତ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ଏହିକ୍ଷଣି"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"ଏହି ଡିଭାଇସ୍‍"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 0cf95753..732b78a 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s ਰਾਹੀਂ ਉਪਲਬਧ"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"ਸਾਈਨ-ਅੱਪ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"ਕਨੈਕਟ ਕੀਤਾ, ਕੋਈ ਇੰਟਰਨੈੱਟ ਨਹੀਂ"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"ਨਿੱਜੀ ਡੋਮੇਨ ਨਾਮ ਪ੍ਰਣਾਲੀ (DNS) ਸਰਵਰ \'ਤੇ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"ਸੀਮਤ ਕਨੈਕਸ਼ਨ"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ਇੰਟਰਨੈੱਟ ਨਹੀਂ"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ਸਾਈਨ-ਇਨ ਲੋੜੀਂਦਾ ਹੈ"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"ਔਸਤ"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"ਤੇਜ਼"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"ਬਹੁਤ ਤੇਜ਼"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"ਡਿਸਕਨੈਕਟ ਕੀਤਾ"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"ਡਿਸਕਨੈਕਟ ਕਰ ਰਿਹਾ ਹੈ..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਬੰਦ ਨਹੀਂ ਕਰਦੇ"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ਹੁਣੇ ਹੀ"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"ਇਹ ਡੀਵਾਈਸ"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index caed8c3..ce49b75 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Dostępne przez %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Kliknij, by się zarejestrować"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Połączono, brak internetu"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Brak dostępu do prywatnego serwera DNS"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Ograniczone połączenie"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Brak internetu"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Musisz się zalogować"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Średnia"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Szybka"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Bardzo szybka"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Rozłączona"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Rozłączanie..."</string>
@@ -467,4 +470,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dopóki nie wyłączysz"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Przed chwilą"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"To urządzenie"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 04a24f1..4b194ec 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponível via %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Toque para se inscrever"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Conectada, sem Internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Não é possível acessar o servidor DNS privado"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Conexão limitada"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Sem Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"É necessário fazer login"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Média"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Rápida"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Muito rápida"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Desconectado"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Desconectando…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Até você desativar"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Agora"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Este dispositivo"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index a206d1a..966ba3f 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponível através de %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Toque para se inscrever"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Ligado, sem Internet."</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Não é possível aceder ao servidor DNS."</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Ligação limitada"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Sem Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"É necessário iniciar sessão"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Média"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Rápida"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Muito rápida"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Desligado"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"A desligar..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Até ser desativado"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Agora mesmo"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Este dispositivo"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 04a24f1..4b194ec 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponível via %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Toque para se inscrever"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Conectada, sem Internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Não é possível acessar o servidor DNS privado"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Conexão limitada"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Sem Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"É necessário fazer login"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Média"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Rápida"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Muito rápida"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Desconectado"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Desconectando…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Até você desativar"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Agora"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Este dispositivo"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 76a56e5..117962d 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponibilă prin %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Atingeți pentru a vă înscrie"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Conectată, fără internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Serverul DNS privat nu poate fi accesat"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Conexiune limitată"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Fără conexiune la internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Trebuie să vă conectați"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Medie"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Rapidă"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Foarte rapidă"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Deconectat"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"În curs de deconectare..."</string>
@@ -466,4 +469,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Până când dezactivați"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Chiar acum"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Acest dispozitiv"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 6e1d29a..fcbbed9 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Доступно через %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Нажмите, чтобы зарегистрироваться"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Подключено, без доступа к Интернету"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Доступа к частному DNS-серверу нет."</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Подключение к сети ограничено."</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Нет подключения к Интернету"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Требуется выполнить вход."</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Средняя"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Быстрая"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Очень быстрая"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Нет подключения"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Отключение..."</string>
@@ -467,4 +470,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Пока вы не отключите"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Только что"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Это устройство"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 186c23a..374e5c4 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s හරහා ලබා ගැනීමට හැකිය"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"ලියාපදිංචි වීමට තට්ටු කරන්න"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"සම්බන්ධයි, අන්තර්ජාලය නැත"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"පුද්ගලික DNS සේවාදායකයට ප්‍රවේශ වීමට නොහැකිය"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"සීමිත සම්බන්ධතාව"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"අන්තර්ජාලය නැත"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"පිරීම අවශ්‍යයි"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"මධ්‍යම"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"වේගවත්"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"ඉතා වේගවත්"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"විසන්ධි වුණි"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"විසන්ධි වෙමින්…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"ඔබ ක්‍රියාවිරහිත කරන තුරු"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"මේ දැන්"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"මෙම උපාංගය"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 9559975..4a660c1 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"K dispozícii prostredníctvom %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Prihláste sa klepnutím"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Pripojené, žiadny internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"K súkromnému serveru DNS sa nepodarilo získať prístup"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Obmedzené pripojenie"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Žiadny internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Vyžaduje sa prihlásenie"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Stredná"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Vysoká"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Veľmi vysoká"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Odpojený"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Prebieha odpájanie..."</string>
@@ -467,4 +470,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dokiaľ túto funkciu nevypnete"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Teraz"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Toto zariadenie"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 62e4ad1..e806fae 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Na voljo prek: %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Dotaknite se, če se želite registrirati"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Vzpostavljena povezava, brez interneta"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Do zasebnega strežnika DNS ni mogoče dostopati"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Omejena povezava"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Brez internetne povezave"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Zahtevana je prijava"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Srednje hitra"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Hitra"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Zelo hitra"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Prekinjena povezava"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Prekinjanje povezave ..."</string>
@@ -467,4 +470,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Dokler ne izklopite"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"pravkar"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Ta naprava"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 0498f31..8aa2917 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"E mundshme përmes %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Trokit për t\'u regjistruar"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"U lidh, por nuk ka internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Serveri privat DNS nuk mund të qaset"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Lidhje e kufizuar"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Nuk ka internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Kërkohet identifikimi"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Mesatare"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"E shpejtë"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Shumë e shpejtë"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Shkëputur"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Po shkëputet..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Deri sa ta çaktivizosh"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Pikërisht tani"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Kjo pajisje"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 3157dee..01c9b80 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Доступна је преко приступне тачке %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Додирните да бисте се регистровали"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Веза је успостављена, нема интернета"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Приступ приватном DNS серверу није успео"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Ограничена веза"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Нема интернета"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Треба да се пријавите"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Средња"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Брза"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Веома брза"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Веза је прекинута"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Прекидање везе..."</string>
@@ -466,4 +469,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Док не искључите"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Управо"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Овај уређај"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 31517b8..0f9abc9 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Tillgängligt via %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Tryck för att logga in"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Ansluten, inget internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Det går inte att komma åt den privata DNS-servern."</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Begränsad anslutning"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Inget internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Inloggning krävs"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Medelsnabb"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Snabb"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Mycket snabb"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Kopplas ifrån"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Kopplar ifrån…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Tills du inaktiverar funktionen"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Nyss"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Den här enheten"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index d73084f..3ccf8a4 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Inapatikana kupitia %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Gusa ili ujisajili"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Imeunganishwa, hakuna intaneti"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Seva ya faragha ya DNS haiwezi kufikiwa"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Muunganisho hafifu"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Hakuna intaneti"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Unahitaji kuingia katika akaunti"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Wastani"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Haraka"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Haraka Sana"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Haijaunganishwa"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Inatenganisha..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Hadi utakapoizima"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Sasa hivi"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Kifaa hiki"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index de70d08..4c6bd22 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s வழியாகக் கிடைக்கிறது"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"பதிவு செய்யத் தட்டவும்"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"இணைக்கப்பட்டுள்ளது, ஆனால் இண்டர்நெட் இல்லை"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"தனிப்பட்ட DNS சேவையகத்தை அணுக இயலாது"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"வரம்பிற்கு உட்பட்ட இணைப்பு"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"இணைய இணைப்பு இல்லை"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"உள்நுழைய வேண்டும்"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"நடுத்தரம்"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"வேகம்"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"மிகவும் வேகமானது"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"தொடர்பு துண்டிக்கப்பட்டது"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"துண்டிக்கிறது..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"ஆஃப் செய்யும் வரை"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"சற்றுமுன்"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"இந்தச் சாதனம்"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 03ae94f..f1f192b 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s ద్వారా అందుబాటులో ఉంది"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"సైన్ అప్ చేయడానికి నొక్కండి"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"కనెక్ట్ చేయబడింది, ఇంటర్నెట్ లేదు"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"ప్రైవేట్ DNS సర్వర్‌ను యాక్సెస్ చేయడం సాధ్యపడదు"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"పరిమిత కనెక్షన్"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ఇంటర్నెట్ లేదు"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"సైన్ ఇన్ చేయాలి"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"మధ్యస్థం"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"వేగవంతం"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"చాలా వేగవంతం"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"డిస్‌కనెక్ట్ చేయబడింది"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"డిస్‌కనెక్ట్ చేస్తోంది..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"మీరు ఆఫ్‌ చేసే వరకు"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ఇప్పుడే"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"ఈ పరికరం"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 1cfe45e..e7d7d5b 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"พร้อมใช้งานผ่านทาง %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"แตะเพื่อลงชื่อสมัครใช้"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"เชื่อมต่อแล้ว ไม่พบอินเทอร์เน็ต"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"เข้าถึงเซิร์ฟเวอร์ DNS ไม่ได้"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"การเชื่อมต่อที่จำกัด"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"ไม่มีอินเทอร์เน็ต"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"ต้องลงชื่อเข้าใช้"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"ปานกลาง"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"เร็ว"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"เร็วมาก"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"ตัดการเชื่อมต่อ"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"กำลังตัดการเชื่อมต่อ..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"จนกว่าคุณจะปิด"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"เมื่อสักครู่"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"อุปกรณ์นี้"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 8b3118b..a221355 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Available sa pamamagitan ng %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"I-tap para mag-sign up"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Nakakonekta, walang internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Hindi ma-access ang pribadong DNS server"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Limitadong koneksyon"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Walang internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Kinakailangang mag-sign in"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Katamtaman"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Mabilis"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Napakabilis"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Hindi nakakonekta"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Nadidiskonekta..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Hanggang sa i-off mo"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Ngayon lang"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Ang device na ito"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 5891c79..49aecf8 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s üzerinden kullanılabilir"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Kaydolmak için dokunun"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Bağlı, internet yok"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Gizli DNS sunucusuna erişilemiyor"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Sınırlı bağlantı"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"İnternet yok"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Oturum açılması gerekiyor"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Orta"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Hızlı"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Çok Hızlı"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Bağlantı kesildi"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Bağlantı kesiliyor…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Siz kapatana kadar"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Az önce"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Bu cihaz"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 0bca307..cf86f4d 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Доступ через %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Торкніться, щоб увійти"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Під’єднано, але немає доступу до Інтернету"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Немає доступу до приватного DNS-сервера"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Обмежене з’єднання"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Немає Інтернету"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Потрібно ввійти в обліковий запис"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Середня"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Швидка"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Дуже швидка"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>: <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Роз’єднано"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Відключення..."</string>
@@ -467,4 +470,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Доки не вимкнути"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Щойно"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Цей пристрій"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 1e27b48..de93a4a 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"‏دستیاب بذریعہ ‎%1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"سائن اپ کے لیے تھپتھپائیں"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"منسلک، انٹرنیٹ نہیں ہے"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"‏نجی DNS سرور تک رسائی حاصل نہیں کی جا سکی"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"محدود کنکشن"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"انٹرنیٹ نہیں ہے"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"سائن ان درکار ہے"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"متوسط"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"تیز"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"بہت تیز"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"منقطع"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"منقطع کیا جارہا ہے…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"یہاں تک کہ آپ آف کر دیں"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"ابھی ابھی"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"یہ آلہ"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 487100c..42847e13 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s orqali ishlaydi"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Yozilish uchun bosing"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Ulangan, lekin internet aloqasi yo‘q"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Xususiy DNS server ishlamayapti"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Cheklangan aloqa"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Internet yo‘q"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Hisob bilan kirish zarur"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"O‘rtacha"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Tez"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Juda tez"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Uzildi"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Uzilyapti…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Rejimdan chiqilgunicha"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Hozir"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Shu qurilma"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index c247617..433e924 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Có sẵn qua %1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Nhấn để đăng ký"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Đã kết nối, không có Internet"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Không thể truy cập máy chủ DNS riêng tư"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Kết nối giới hạn"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Không có Internet"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Yêu cầu đăng nhập"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Trung bình"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Nhanh"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Rất nhanh"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Đã ngắt kết nối"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Đang ngắt kết nối…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Cho đến khi bạn tắt"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Vừa xong"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Thiết bị này"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index dddc107..c967372 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"可通过%1$s连接"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"点按即可注册"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"已连接,但无法访问互联网"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"无法访问私人 DNS 服务器"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"网络连接受限"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"无法访问互联网"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"必须登录"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"适中"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"快"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"很快"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"已断开连接"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"正在断开连接..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"直到您将其关闭"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"刚刚"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"此设备"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 8560e22..325425c 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"可透過 %1$s 連線"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"輕按即可登入"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"已連線,但沒有互聯網"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"無法存取私人 DNS 伺服器"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"連線受限"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"沒有互聯網連線"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"必須登入"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"適中"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"快"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"非常快"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"已中斷連線"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"正在中斷連線..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"直至您關閉為止"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"剛剛"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"此裝置"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 404aa19..82477ea 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"可透過 %1$s 使用"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"輕觸即可註冊"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"已連線,沒有網際網路"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"無法存取私人 DNS 伺服器"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"連線能力受限"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"沒有網際網路連線"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"必須登入"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"適中"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"快"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"非常快"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"已中斷連線"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"正在中斷連線…"</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"直到你關閉為止"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"剛剛"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"這個裝置"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 542332f..d4e8166 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -43,6 +43,7 @@
     <string name="available_via_passpoint" msgid="1617440946846329613">"Iyatholakala nge-%1$s"</string>
     <string name="tap_to_sign_up" msgid="6449724763052579434">"Thepha ukuze ubhalisele"</string>
     <string name="wifi_connected_no_internet" msgid="8202906332837777829">"Kuxhunyiwe, ayikho i-inthanethi"</string>
+    <string name="private_dns_broken" msgid="7356676011023412490">"Iseva eyimfihlo ye-DNS ayikwazi ukufinyelelwa"</string>
     <string name="wifi_limited_connection" msgid="7717855024753201527">"Iqoqo elikhawulelwe"</string>
     <string name="wifi_status_no_internet" msgid="5784710974669608361">"Ayikho i-inthanethi"</string>
     <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Ukungena ngemvume kuyadingeka"</string>
@@ -60,6 +61,8 @@
     <string name="speed_label_medium" msgid="3175763313268941953">"Okumaphakathi"</string>
     <string name="speed_label_fast" msgid="7715732164050975057">"Sheshayo"</string>
     <string name="speed_label_very_fast" msgid="2265363430784523409">"Kushesha kakhulu"</string>
+    <!-- no translation found for wifi_passpoint_expired (1711402866023391443) -->
+    <skip />
     <string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="6557104142667339895">"Ayixhunyiwe"</string>
     <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Inqamula uxhumano kwi-inthanethi..."</string>
@@ -465,4 +468,6 @@
     <string name="zen_mode_forever" msgid="2704305038191592967">"Uze uvale isikrini"</string>
     <string name="time_unit_just_now" msgid="6363336622778342422">"Khona manje"</string>
     <string name="media_transfer_this_device_name" msgid="1636276898262571213">"Le divayisi"</string>
+    <!-- no translation found for profile_connect_timeout_subtext (2401801610868184557) -->
+    <skip />
 </resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 1f923af..a1ef831 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -127,6 +127,9 @@
     <!-- Summary for Connected wifi network without internet -->
     <string name="wifi_connected_no_internet">Connected, no internet</string>
 
+    <!-- Summary for connected network without internet due to private dns validation failed [CHAR LIMIT=NONE] -->
+    <string name="private_dns_broken">Private DNS server cannot be accessed</string>
+
     <!-- Summary for connected wifi network with partial internet connectivity [CHAR LIMIT=50] -->
     <string name="wifi_limited_connection">Limited connection</string>
 
@@ -168,6 +171,9 @@
     <!-- Speed label for very fast network speed -->
     <string name="speed_label_very_fast">Very Fast</string>
 
+    <!-- Passpoint summary for an expired passpoint [CHAR LIMIT=40] -->
+    <string name="wifi_passpoint_expired">Expired</string>
+
     <!-- Summary text separator for preferences including a short description (eg. "Fast / Connected"). -->
     <string name="preference_summary_default_combination"><xliff:g id="state" example="ON">%1$s</xliff:g> / <xliff:g id="description" example="High accuracy mode">%2$s</xliff:g></string>
 
@@ -1180,4 +1186,7 @@
 
     <!-- Name of the this device. [CHAR LIMIT=30] -->
     <string name="media_transfer_this_device_name">This device</string>
+
+    <!-- Warning message to tell user is have problem during profile connect, it need to turn off device and back on. [CHAR_LIMIT=NONE] -->
+    <string name="profile_connect_timeout_subtext">Problem connecting. Turn device off &amp; back on</string>
 </resources>
diff --git a/packages/SettingsLib/search/src/com/android/settingslib/search/Indexable.java b/packages/SettingsLib/search/src/com/android/settingslib/search/Indexable.java
index e68b0d1..8b17ddf 100644
--- a/packages/SettingsLib/search/src/com/android/settingslib/search/Indexable.java
+++ b/packages/SettingsLib/search/src/com/android/settingslib/search/Indexable.java
@@ -56,6 +56,16 @@
         List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled);
 
         /**
+         * Return a list of dynamic raw data for indexing. See {@link SearchIndexableRaw}
+         *
+         * @param context the context.
+         * @param enabled hint telling if the data needs to be considered into the search results
+         *                or not.
+         * @return a list of {@link SearchIndexableRaw} references. Can be null.
+         */
+        List<SearchIndexableRaw> getDynamicRawDataToIndex(Context context, boolean enabled);
+
+        /**
          * Return a list of data keys that cannot be indexed. See {@link SearchIndexableRaw}
          *
          * @param context the context.
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 98db7c8..2507a34 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -24,6 +24,9 @@
 import android.bluetooth.BluetoothUuid;
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
 import android.os.ParcelUuid;
 import android.os.SystemClock;
 import android.text.TextUtils;
@@ -55,6 +58,7 @@
     // Some Hearing Aids (especially the 2nd device) needs more time to do service discovery
     private static final long MAX_HEARING_AIDS_DELAY_FOR_AUTO_CONNECT = 15000;
     private static final long MAX_HOGP_DELAY_FOR_AUTO_CONNECT = 30000;
+    private static final long MAX_MEDIA_PROFILE_CONNECT_DELAY = 60000;
 
     private final Context mContext;
     private final BluetoothAdapter mLocalAdapter;
@@ -90,9 +94,35 @@
     private boolean mIsActiveDeviceA2dp = false;
     private boolean mIsActiveDeviceHeadset = false;
     private boolean mIsActiveDeviceHearingAid = false;
+    // Media profile connect state
+    private boolean mIsA2dpProfileConnectedFail = false;
+    private boolean mIsHeadsetProfileConnectedFail = false;
+    private boolean mIsHearingAidProfileConnectedFail = false;
     // Group second device for Hearing Aid
     private CachedBluetoothDevice mSubDevice;
 
+    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case BluetoothProfile.A2DP:
+                    mIsA2dpProfileConnectedFail = true;
+                    break;
+                case BluetoothProfile.HEADSET:
+                    mIsHeadsetProfileConnectedFail = true;
+                    break;
+                case BluetoothProfile.HEARING_AID:
+                    mIsHearingAidProfileConnectedFail = true;
+                    break;
+                default:
+                    Log.w(TAG, "handleMessage(): unknown message : " + msg.what);
+                    break;
+            }
+            Log.w(TAG, "Connect to profile : " + msg.what + " timeout, show error message !");
+            refresh();
+        }
+    };
+
     CachedBluetoothDevice(Context context, LocalBluetoothProfileManager profileManager,
             BluetoothDevice device) {
         mContext = context;
@@ -133,6 +163,35 @@
         }
 
         synchronized (mProfileLock) {
+            if (profile instanceof A2dpProfile || profile instanceof HeadsetProfile
+                    || profile instanceof HearingAidProfile) {
+                setProfileConnectedStatus(profile.getProfileId(), false);
+                switch (newProfileState) {
+                    case BluetoothProfile.STATE_CONNECTED:
+                        mHandler.removeMessages(profile.getProfileId());
+                        break;
+                    case BluetoothProfile.STATE_CONNECTING:
+                        mHandler.sendEmptyMessageDelayed(profile.getProfileId(),
+                                MAX_MEDIA_PROFILE_CONNECT_DELAY);
+                        break;
+                    case BluetoothProfile.STATE_DISCONNECTING:
+                        if (mHandler.hasMessages(profile.getProfileId())) {
+                            mHandler.removeMessages(profile.getProfileId());
+                        }
+                        break;
+                    case BluetoothProfile.STATE_DISCONNECTED:
+                        if (mHandler.hasMessages(profile.getProfileId())) {
+                            mHandler.removeMessages(profile.getProfileId());
+                            setProfileConnectedStatus(profile.getProfileId(), true);
+                        }
+                        break;
+                    default:
+                        Log.w(TAG, "onProfileStateChanged(): unknown profile state : "
+                                + newProfileState);
+                        break;
+                }
+            }
+
             if (newProfileState == BluetoothProfile.STATE_CONNECTED) {
                 if (profile instanceof MapProfile) {
                     profile.setPreferred(mDevice, true);
@@ -162,6 +221,24 @@
         fetchActiveDevices();
     }
 
+    @VisibleForTesting
+    void setProfileConnectedStatus(int profileId, boolean isFailed) {
+        switch (profileId) {
+            case BluetoothProfile.A2DP:
+                mIsA2dpProfileConnectedFail = isFailed;
+                break;
+            case BluetoothProfile.HEADSET:
+                mIsHeadsetProfileConnectedFail = isFailed;
+                break;
+            case BluetoothProfile.HEARING_AID:
+                mIsHearingAidProfileConnectedFail = isFailed;
+                break;
+            default:
+                Log.w(TAG, "setProfileConnectedStatus(): unknown profile id : " + profileId);
+                break;
+        }
+    }
+
     public void disconnect() {
         synchronized (mProfileLock) {
             for (LocalBluetoothProfile profile : mProfiles) {
@@ -844,6 +921,10 @@
         int leftBattery = -1;
         int rightBattery = -1;
 
+        if (isProfileConnectedFail() && isConnected()) {
+            return mContext.getString(R.string.profile_connect_timeout_subtext);
+        }
+
         synchronized (mProfileLock) {
             for (LocalBluetoothProfile profile : getProfiles()) {
                 int connectionStatus = getProfileConnectionState(profile);
@@ -943,6 +1024,11 @@
         return leftBattery >= 0 && rightBattery >= 0;
     }
 
+    private boolean isProfileConnectedFail() {
+        return mIsA2dpProfileConnectedFail || mIsHearingAidProfileConnectedFail
+                || mIsHeadsetProfileConnectedFail;
+    }
+
     /**
      * @return resource for android auto string that describes the connection state of this device.
      */
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
index 4e052f1..69f1c17 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
@@ -18,6 +18,7 @@
 import android.os.Handler;
 import android.os.Looper;
 
+import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
@@ -64,11 +65,16 @@
      * @Return A future of the task that can be monitored for updates or cancelled.
      */
     public static Future postOnBackgroundThread(Runnable runnable) {
-        if (sThreadExecutor == null) {
-            sThreadExecutor = Executors.newFixedThreadPool(
-                    Runtime.getRuntime().availableProcessors());
-        }
-        return sThreadExecutor.submit(runnable);
+        return getThreadExecutor().submit(runnable);
+    }
+
+    /**
+     * Posts callable in background using shared background thread pool.
+     *
+     * @Return A future of the task that can be monitored for updates or cancelled.
+     */
+    public static Future postOnBackgroundThread(Callable callable) {
+        return getThreadExecutor().submit(callable);
     }
 
     /**
@@ -78,4 +84,11 @@
         getUiThreadHandler().post(runnable);
     }
 
+    private static synchronized ExecutorService getThreadExecutor() {
+        if (sThreadExecutor == null) {
+            sThreadExecutor = Executors.newFixedThreadPool(
+                    Runtime.getRuntime().availableProcessors());
+        }
+        return sThreadExecutor;
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 81d1ea5..ab274b5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -50,6 +50,7 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
@@ -142,6 +143,16 @@
         int VERY_FAST = 30;
     }
 
+    @IntDef({PasspointConfigurationVersion.INVALID,
+            PasspointConfigurationVersion.NO_OSU_PROVISIONED,
+            PasspointConfigurationVersion.OSU_PROVISIONED})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PasspointConfigurationVersion {
+        int INVALID = 0;
+        int NO_OSU_PROVISIONED = 1; // R1.
+        int OSU_PROVISIONED = 2;    // R2 or R3.
+    }
+
     /** The underlying set of scan results comprising this AccessPoint. */
     @GuardedBy("mLock")
     private final ArraySet<ScanResult> mScanResults = new ArraySet<>();
@@ -176,6 +187,9 @@
     static final String KEY_CARRIER_AP_EAP_TYPE = "key_carrier_ap_eap_type";
     static final String KEY_CARRIER_NAME = "key_carrier_name";
     static final String KEY_EAPTYPE = "eap_psktype";
+    static final String KEY_SUBSCRIPTION_EXPIRATION_TIME_IN_MILLIS  =
+            "key_subscription_expiration_time_in_millis";
+    static final String KEY_PASSPOINT_CONFIGURATION_VERSION = "key_passpoint_configuration_version";
     static final AtomicInteger sLastId = new AtomicInteger(0);
 
     /*
@@ -250,6 +264,9 @@
     private String mFqdn;
     private String mProviderFriendlyName;
     private boolean mIsRoaming = false;
+    private long mSubscriptionExpirationTimeInMillis;
+    @PasspointConfigurationVersion private int mPasspointConfigurationVersion =
+            PasspointConfigurationVersion.INVALID;
 
     private boolean mIsCarrierAp = false;
 
@@ -322,6 +339,13 @@
         if (savedState.containsKey(KEY_CARRIER_NAME)) {
             mCarrierName = savedState.getString(KEY_CARRIER_NAME);
         }
+        if (savedState.containsKey(KEY_SUBSCRIPTION_EXPIRATION_TIME_IN_MILLIS)) {
+            mSubscriptionExpirationTimeInMillis =
+                    savedState.getLong(KEY_SUBSCRIPTION_EXPIRATION_TIME_IN_MILLIS);
+        }
+        if (savedState.containsKey(KEY_PASSPOINT_CONFIGURATION_VERSION)) {
+            mPasspointConfigurationVersion = savedState.getInt(KEY_PASSPOINT_CONFIGURATION_VERSION);
+        }
         update(mConfig, mInfo, mNetworkInfo);
 
         // Calculate required fields
@@ -347,6 +371,12 @@
         mContext = context;
         mFqdn = config.getHomeSp().getFqdn();
         mProviderFriendlyName = config.getHomeSp().getFriendlyName();
+        mSubscriptionExpirationTimeInMillis = config.getSubscriptionExpirationTimeInMillis();
+        if (config.isOsuProvisioned()) {
+            mPasspointConfigurationVersion = PasspointConfigurationVersion.OSU_PROVISIONED;
+        } else {
+            mPasspointConfigurationVersion = PasspointConfigurationVersion.NO_OSU_PROVISIONED;
+        }
         updateKey();
     }
 
@@ -990,6 +1020,10 @@
                 return mContext.getString(R.string.saved_network, appInfo.loadLabel(pm));
             }
         }
+
+        if (isPasspointConfigurationR1() && isExpired()) {
+            return mContext.getString(R.string.wifi_passpoint_expired);
+        }
         return "";
     }
 
@@ -1020,6 +1054,10 @@
      * Returns the summary for the AccessPoint.
      */
     public String getSettingsSummary(boolean convertSavedAsDisconnected) {
+        if (isPasspointConfigurationR1() && isExpired()) {
+            return mContext.getString(R.string.wifi_passpoint_expired);
+        }
+
         // Update to new summary
         StringBuilder summary = new StringBuilder();
 
@@ -1166,6 +1204,30 @@
     }
 
     /**
+     * Return true if this AccessPoint is expired.
+     */
+    public boolean isExpired() {
+        if (mSubscriptionExpirationTimeInMillis <= 0) {
+            // Expiration time not specified.
+            return false;
+        } else {
+            return System.currentTimeMillis() >= mSubscriptionExpirationTimeInMillis;
+        }
+    }
+
+    public boolean isPasspointConfigurationR1() {
+        return mPasspointConfigurationVersion == PasspointConfigurationVersion.NO_OSU_PROVISIONED;
+    }
+
+    /**
+     * Return true if {@link PasspointConfiguration#isOsuProvisioned} is true, this may refer to R2
+     * or R3.
+     */
+    public boolean isPasspointConfigurationOsuProvisioned() {
+        return mPasspointConfigurationVersion == PasspointConfigurationVersion.OSU_PROVISIONED;
+    }
+
+    /**
      * Starts the OSU Provisioning flow.
      */
     public void startOsuProvisioning(@Nullable WifiManager.ActionListener connectListener) {
@@ -1263,6 +1325,9 @@
         savedState.putBoolean(KEY_IS_CARRIER_AP, mIsCarrierAp);
         savedState.putInt(KEY_CARRIER_AP_EAP_TYPE, mCarrierApEapType);
         savedState.putString(KEY_CARRIER_NAME, mCarrierName);
+        savedState.putLong(KEY_SUBSCRIPTION_EXPIRATION_TIME_IN_MILLIS,
+                mSubscriptionExpirationTimeInMillis);
+        savedState.putInt(KEY_PASSPOINT_CONFIGURATION_VERSION, mPasspointConfigurationVersion);
     }
 
     public void setListener(AccessPointListener listener) {
@@ -1568,7 +1633,13 @@
                         NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY)) {
                     return context.getString(R.string.wifi_limited_connection);
                 } else if (!nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
-                    return context.getString(R.string.wifi_connected_no_internet);
+                    final String mode = Settings.Global.getString(context.getContentResolver(),
+                            Settings.Global.PRIVATE_DNS_MODE);
+                    if (nc.isPrivateDnsBroken()) {
+                        return context.getString(R.string.private_dns_broken);
+                    } else {
+                        return context.getString(R.string.wifi_connected_no_internet);
+                    }
                 }
             }
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 5352936..b11585a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -31,6 +31,7 @@
 import android.net.wifi.WifiSsid;
 import android.os.Handler;
 import android.os.Looper;
+import android.provider.Settings;
 
 import com.android.settingslib.R;
 
@@ -163,7 +164,13 @@
                 statusLabel = mContext.getString(R.string.wifi_limited_connection);
                 return;
             } else if (!networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
-                statusLabel = mContext.getString(R.string.wifi_status_no_internet);
+                final String mode = Settings.Global.getString(mContext.getContentResolver(),
+                        Settings.Global.PRIVATE_DNS_MODE);
+                if (networkCapabilities.isPrivateDnsBroken()) {
+                    statusLabel = mContext.getString(R.string.private_dns_broken);
+                } else {
+                    statusLabel = mContext.getString(R.string.wifi_status_no_internet);
+                }
                 return;
             }
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
index 658a0b5..6f19559 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
@@ -93,7 +93,7 @@
             if (bssid != null) {
                 visibility.append(" ").append(bssid);
             }
-            visibility.append(" technology = ").append(info.getWifiTechnology());
+            visibility.append(" standard = ").append(info.getWifiStandard());
             visibility.append(" rssi=").append(info.getRssi());
             visibility.append(" ");
             visibility.append(" score=").append(info.score);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 93dcbfe..5c89a01 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -31,6 +32,8 @@
 import android.content.Context;
 import android.media.AudioManager;
 
+import com.android.settingslib.R;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -922,4 +925,16 @@
         assertThat(subCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_1);
         assertThat(subCachedDevice.mDevice).isEqualTo(mDevice);
     }
+
+    @Test
+    public void getConnectionSummary_profileConnectedFail_showErrorMessage() {
+        final A2dpProfile profle = mock(A2dpProfile.class);
+        mCachedDevice.onProfileStateChanged(profle, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice.setProfileConnectedStatus(BluetoothProfile.A2DP, true);
+
+        when(profle.getConnectionStatus(mDevice)).thenReturn(BluetoothProfile.STATE_CONNECTED);
+
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                mContext.getString(R.string.profile_connect_timeout_subtext));
+    }
 }
diff --git a/packages/SettingsProvider/OWNERS b/packages/SettingsProvider/OWNERS
new file mode 100644
index 0000000..2054129
--- /dev/null
+++ b/packages/SettingsProvider/OWNERS
@@ -0,0 +1,3 @@
+hackbod@google.com
+svetoslavganov@google.com
+moltmann@google.com
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index f7fc0c5..0c3254a 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -228,5 +228,6 @@
         VALIDATORS.put(Secure.GLOBAL_ACTIONS_PANEL_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.AWARE_LOCK_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.DISPLAY_DENSITY_FORCED, NON_NEGATIVE_INTEGER_VALIDATOR);
+        VALIDATORS.put(Secure.TAP_GESTURE, BOOLEAN_VALIDATOR);
     }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
index 8fb879d..1e75fe7 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -248,7 +248,7 @@
                 Bundle args = new Bundle();
                 args.putInt(Settings.CALL_METHOD_USER_KEY,
                         ActivityManager.getService().getCurrentUser().id);
-                Bundle b = provider.call(resolveCallingPackage(), Settings.AUTHORITY,
+                Bundle b = provider.call(resolveCallingPackage(), null, Settings.AUTHORITY,
                         Settings.CALL_METHOD_DELETE_CONFIG, compositeKey, args);
                 success = (b != null && b.getInt(SettingsProvider.RESULT_ROWS_DELETED) == 1);
             } catch (RemoteException e) {
@@ -264,7 +264,7 @@
                 Bundle args = new Bundle();
                 args.putInt(Settings.CALL_METHOD_USER_KEY,
                         ActivityManager.getService().getCurrentUser().id);
-                Bundle b = provider.call(resolveCallingPackage(), Settings.AUTHORITY,
+                Bundle b = provider.call(resolveCallingPackage(), null, Settings.AUTHORITY,
                         Settings.CALL_METHOD_LIST_CONFIG, null, args);
                 if (b != null) {
                     Map<String, String> flagsToValues =
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index e24d387..55a51da 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -56,8 +56,6 @@
                 ConfigSettingsProto.CONNECTIVITY_SETTINGS);
         namespaceToFieldMap.put(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
                 ConfigSettingsProto.CONTENT_CAPTURE_SETTINGS);
-        namespaceToFieldMap.put(DeviceConfig.NAMESPACE_DEX_BOOT,
-                ConfigSettingsProto.DEX_BOOT_SETTINGS);
         namespaceToFieldMap.put(DeviceConfig.NAMESPACE_GAME_DRIVER,
                 ConfigSettingsProto.GAME_DRIVER_SETTINGS);
         namespaceToFieldMap.put(DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT,
@@ -548,6 +546,9 @@
         dumpSetting(s, p,
                 Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS,
                 GlobalSettingsProto.Development.FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS);
+        dumpSetting(s, p,
+                Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM,
+                GlobalSettingsProto.Development.ENABLE_SIZECOMPAT_FREEFORM);
         p.end(developmentToken);
 
         final long deviceToken = p.start(GlobalSettingsProto.DEVICE);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 80faf476..7765935 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1080,6 +1080,9 @@
             Slog.v(LOG_TAG, "getAllConfigFlags() for " + prefix);
         }
 
+        DeviceConfig.enforceReadPermission(getContext(),
+                prefix != null ? prefix.split("/")[0] : null);
+
         synchronized (mLock) {
             // Get the settings.
             SettingsState settingsState = mSettingsRegistry.getSettingsLocked(
@@ -2112,10 +2115,7 @@
     }
 
     private static String getSettingPrefix(Bundle args) {
-        String prefix = (args != null) ? args.getString(Settings.CALL_METHOD_PREFIX_KEY) : null;
-        // Append '/' to ensure we only match properties with this exact prefix.
-        // i.e. "foo" should match "foo/property" but not "foobar/property"
-        return prefix != null ? prefix + "/" : null;
+        return (args != null) ? args.getString(Settings.CALL_METHOD_PREFIX_KEY) : null;
     }
 
     private static boolean getSettingMakeDefault(Bundle args) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
index 36360a3..3b3ca5b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
@@ -309,7 +309,7 @@
             try {
                 Bundle arg = new Bundle();
                 arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
-                Bundle result = provider.call(resolveCallingPackage(), Settings.AUTHORITY,
+                Bundle result = provider.call(resolveCallingPackage(), null, Settings.AUTHORITY,
                         callListCommand, null, arg);
                 lines.addAll(result.getStringArrayList(SettingsProvider.RESULT_SETTINGS_LIST));
                 Collections.sort(lines);
@@ -334,7 +334,7 @@
             try {
                 Bundle arg = new Bundle();
                 arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
-                Bundle b = provider.call(resolveCallingPackage(), Settings.AUTHORITY,
+                Bundle b = provider.call(resolveCallingPackage(), null, Settings.AUTHORITY,
                         callGetCommand, key, arg);
                 if (b != null) {
                     result = b.getPairValue();
@@ -372,7 +372,7 @@
                 if (makeDefault) {
                     arg.putBoolean(Settings.CALL_METHOD_MAKE_DEFAULT_KEY, true);
                 }
-                provider.call(resolveCallingPackage(), Settings.AUTHORITY,
+                provider.call(resolveCallingPackage(), null, Settings.AUTHORITY,
                         callPutCommand, key, arg);
             } catch (RemoteException e) {
                 throw new RuntimeException("Failed in IPC", e);
@@ -396,7 +396,7 @@
             try {
                 Bundle arg = new Bundle();
                 arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
-                Bundle result = provider.call(resolveCallingPackage(), Settings.AUTHORITY,
+                Bundle result = provider.call(resolveCallingPackage(), null, Settings.AUTHORITY,
                         callDeleteCommand, key, arg);
                 return result.getInt(SettingsProvider.RESULT_ROWS_DELETED);
             } catch (RemoteException e) {
@@ -423,7 +423,7 @@
                 }
                 String packageName = mPackageName != null ? mPackageName : resolveCallingPackage();
                 arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
-                provider.call(packageName, Settings.AUTHORITY, callResetCommand, null, arg);
+                provider.call(packageName, null, Settings.AUTHORITY, callResetCommand, null, arg);
             } catch (RemoteException e) {
                 throw new RuntimeException("Failed in IPC", e);
             }
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 179ba8a..10d990a 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -222,6 +222,7 @@
                     Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS,
                     Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES,
                     Settings.Global.DEVELOPMENT_FORCE_RTL,
+                    Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM,
                     Settings.Global.DEVELOPMENT_SETTINGS_ENABLED,
                     Settings.Global.DEVICE_DEMO_MODE,
                     Settings.Global.DEVICE_IDLE_CONSTANTS,
@@ -731,7 +732,8 @@
                  Settings.Secure.SILENCE_GESTURE,
                  Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE,
                  Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE,
-                 Settings.Secure.FACE_UNLOCK_RE_ENROLL);
+                 Settings.Secure.FACE_UNLOCK_RE_ENROLL,
+                 Settings.Secure.TAP_GESTURE);
 
     @Test
     public void systemSettingsBackedUpOrBlacklisted() {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 54e291f..c59f342 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -180,6 +180,8 @@
     <uses-permission android:name="android.permission.MANAGE_WIFI_WHEN_WIRELESS_CONSENT_REQUIRED" />
     <!-- Permission needed to invoke DynamicSystem (AOT) -->
     <uses-permission android:name="android.permission.INSTALL_DYNAMIC_SYSTEM" />
+    <!-- Used to clean up heap dumps on boot. -->
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
 
 
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
@@ -209,7 +211,7 @@
 
     <!-- Permission required to test ExplicitHealthCheckServiceImpl. -->
     <uses-permission android:name="android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE" />
-    
+
     <!-- Permission required for CTS test - CrossProfileAppsHostSideTest -->
     <uses-permission android:name="android.permission.INTERACT_ACROSS_PROFILES"/>
 
@@ -239,6 +241,11 @@
             </intent-filter>
         </provider>
 
+        <provider android:name=".HeapDumpProvider"
+                  android:authorities="com.android.shell.heapdump"
+                  android:grantUriPermissions="true"
+                  android:exported="true" />
+
         <activity
             android:name=".BugreportWarningActivity"
             android:theme="@*android:style/Theme.DeviceDefault.Dialog.Alert.DayNight"
@@ -246,6 +253,14 @@
             android:excludeFromRecents="true"
             android:exported="false" />
 
+        <activity android:name=".HeapDumpActivity"
+                  android:theme="@*android:style/Theme.Translucent.NoTitleBar"
+                  android:label="@*android:string/dump_heap_title"
+                  android:finishOnCloseSystemDialogs="true"
+                  android:noHistory="true"
+                  android:excludeFromRecents="true"
+                  android:exported="false" />
+
         <receiver
             android:name=".BugreportRequestedReceiver"
             android:permission="android.permission.TRIGGER_SHELL_BUGREPORT">
@@ -254,6 +269,16 @@
             </intent-filter>
         </receiver>
 
+        <receiver
+            android:name=".HeapDumpReceiver"
+            android:permission="android.permission.DUMP">
+            <intent-filter>
+                <action android:name="android.intent.action.BOOT_COMPLETED" />
+                <action android:name="com.android.internal.intent.action.HEAP_DUMP_FINISHED" />
+                <action android:name="com.android.shell.action.DELETE_HEAP_DUMP" />
+            </intent-filter>
+        </receiver>
+
         <service
             android:name=".BugreportProgressService"
             android:exported="false"/>
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 1b35770..30ad9c5 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -1560,7 +1560,7 @@
         return false;
     }
 
-    private static boolean isTv(Context context) {
+    static boolean isTv(Context context) {
         return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
     }
 
diff --git a/packages/Shell/src/com/android/shell/HeapDumpActivity.java b/packages/Shell/src/com/android/shell/HeapDumpActivity.java
new file mode 100644
index 0000000..0ff0d33
--- /dev/null
+++ b/packages/Shell/src/com/android/shell/HeapDumpActivity.java
@@ -0,0 +1,142 @@
+/*
+ * 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.shell;
+
+import static com.android.shell.HeapDumpProvider.makeUri;
+import static com.android.shell.HeapDumpReceiver.ACTION_DELETE_HEAP_DUMP;
+import static com.android.shell.HeapDumpReceiver.EXTRA_IS_USER_INITIATED;
+import static com.android.shell.HeapDumpReceiver.EXTRA_PROCESS_NAME;
+import static com.android.shell.HeapDumpReceiver.EXTRA_REPORT_PACKAGE;
+import static com.android.shell.HeapDumpReceiver.EXTRA_SIZE_BYTES;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.AlertDialog;
+import android.content.ActivityNotFoundException;
+import android.content.ClipData;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Process;
+import android.util.DebugUtils;
+import android.util.Log;
+
+import com.android.internal.R;
+
+/**
+ * This activity is displayed when the system has collected a heap dump.
+ */
+public class HeapDumpActivity extends Activity {
+    private static final String TAG = "HeapDumpActivity";
+
+    static final String KEY_URI = "uri";
+
+    private AlertDialog mDialog;
+    private Uri mDumpUri;
+    private boolean mHandled = false;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        String process = getIntent().getStringExtra(EXTRA_PROCESS_NAME);
+        long size = getIntent().getLongExtra(EXTRA_SIZE_BYTES, 0);
+        final boolean isUserInitiated = getIntent().getBooleanExtra(EXTRA_IS_USER_INITIATED, false);
+        final int uid = getIntent().getIntExtra(Intent.EXTRA_UID, 0);
+        final boolean isSystemProcess = uid == Process.SYSTEM_UID;
+        mDumpUri = makeUri(process);
+        final String procDisplayName = isSystemProcess
+                ? getString(com.android.internal.R.string.android_system_label)
+                : process;
+
+        final Intent sendIntent = new Intent();
+        ClipData clip = ClipData.newUri(getContentResolver(), "Heap Dump", mDumpUri);
+        sendIntent.setClipData(clip);
+        sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        sendIntent.setType(clip.getDescription().getMimeType(0));
+        sendIntent.putExtra(Intent.EXTRA_STREAM, mDumpUri);
+
+        String directLaunchPackage = getIntent().getStringExtra(EXTRA_REPORT_PACKAGE);
+        if (directLaunchPackage != null) {
+            sendIntent.setAction(ActivityManager.ACTION_REPORT_HEAP_LIMIT);
+            sendIntent.setPackage(directLaunchPackage);
+            try {
+                startActivity(sendIntent);
+                mHandled = true;
+                finish();
+                return;
+            } catch (ActivityNotFoundException e) {
+                Log.e(TAG, "Unable to direct launch to " + directLaunchPackage, e);
+            }
+        }
+
+        final int messageId;
+        if (isUserInitiated) {
+            messageId = com.android.internal.R.string.dump_heap_ready_text;
+        } else if (isSystemProcess) {
+            messageId = com.android.internal.R.string.dump_heap_system_text;
+        } else {
+            messageId = com.android.internal.R.string.dump_heap_text;
+        }
+        mDialog = new AlertDialog.Builder(this, android.R.style.Theme_Material_Light_Dialog_Alert)
+                .setTitle(com.android.internal.R.string.dump_heap_title)
+                .setMessage(getString(messageId, procDisplayName,
+                        DebugUtils.sizeValueToString(size, null)))
+                .setNegativeButton(android.R.string.cancel, (dialog, which) -> {
+                    mHandled = true;
+                    finish();
+                })
+                .setNeutralButton(R.string.delete, (dialog, which) -> {
+                    mHandled = true;
+                    Intent deleteIntent = new Intent(ACTION_DELETE_HEAP_DUMP);
+                    deleteIntent.setClass(getApplicationContext(), HeapDumpReceiver.class);
+                    deleteIntent.putExtra(KEY_URI, mDumpUri.toString());
+                    sendBroadcast(deleteIntent);
+                    finish();
+                })
+                .setPositiveButton(android.R.string.ok, (dialog, which) -> {
+                    mHandled = true;
+                    sendIntent.setAction(Intent.ACTION_SEND);
+                    sendIntent.setPackage(null);
+                    startActivity(Intent.createChooser(sendIntent,
+                            getText(com.android.internal.R.string.dump_heap_title)));
+                    finish();
+                })
+                .show();
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        if (!isChangingConfigurations()) {
+            if (!mHandled) {
+                Intent deleteIntent = new Intent(ACTION_DELETE_HEAP_DUMP);
+                deleteIntent.setClass(getApplicationContext(), HeapDumpReceiver.class);
+                deleteIntent.putExtra(KEY_URI, mDumpUri.toString());
+                sendBroadcast(deleteIntent);
+            }
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        if (mDialog != null) {
+            mDialog.dismiss();
+        }
+    }
+}
diff --git a/packages/Shell/src/com/android/shell/HeapDumpProvider.java b/packages/Shell/src/com/android/shell/HeapDumpProvider.java
new file mode 100644
index 0000000..3eceb91
--- /dev/null
+++ b/packages/Shell/src/com/android/shell/HeapDumpProvider.java
@@ -0,0 +1,101 @@
+/*
+ * 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.shell;
+
+import android.annotation.NonNull;
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/** ContentProvider to write and access heap dumps. */
+public class HeapDumpProvider extends ContentProvider {
+    private static final String FILENAME_SUFFIX = "_javaheap.bin";
+    private static final Object sLock = new Object();
+
+    private File mRoot;
+
+    @Override
+    public boolean onCreate() {
+        synchronized (sLock) {
+            mRoot = new File(getContext().createCredentialProtectedStorageContext().getFilesDir(),
+                    "heapdumps");
+            return mRoot.mkdir();
+        }
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        return null;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        return "application/octet-stream";
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        throw new UnsupportedOperationException("Insert not allowed.");
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        String path = sanitizePath(uri.getEncodedPath());
+        String tag = Uri.decode(path);
+        return (new File(mRoot, tag)).delete() ? 1 : 0;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException("Update not allowed.");
+    }
+
+    @Override
+    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
+        String path = sanitizePath(uri.getEncodedPath());
+        String tag = Uri.decode(path);
+        final int pMode;
+        if (Binder.getCallingUid() == Process.SYSTEM_UID) {
+            pMode = ParcelFileDescriptor.MODE_CREATE
+                    | ParcelFileDescriptor.MODE_TRUNCATE
+                    | ParcelFileDescriptor.MODE_WRITE_ONLY;
+        } else {
+            pMode = ParcelFileDescriptor.MODE_READ_ONLY;
+        }
+
+        synchronized (sLock) {
+            return ParcelFileDescriptor.open(new File(mRoot, tag), pMode);
+        }
+    }
+
+    @NonNull
+    static Uri makeUri(@NonNull String procName) {
+        return Uri.parse("content://com.android.shell.heapdump/" + procName + FILENAME_SUFFIX);
+    }
+
+    private String sanitizePath(String path) {
+        return path.replaceAll("[^a-zA-Z0-9_.]", "");
+    }
+}
diff --git a/packages/Shell/src/com/android/shell/HeapDumpReceiver.java b/packages/Shell/src/com/android/shell/HeapDumpReceiver.java
new file mode 100644
index 0000000..858c521
--- /dev/null
+++ b/packages/Shell/src/com/android/shell/HeapDumpReceiver.java
@@ -0,0 +1,188 @@
+/*
+ * 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.shell;
+
+import static com.android.shell.BugreportProgressService.isTv;
+
+import android.annotation.Nullable;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.FileUtils;
+import android.os.Process;
+import android.text.format.DateUtils;
+import android.util.Log;
+
+import java.io.File;
+
+/**
+ * Receiver that handles finished heap dumps.
+ */
+public class HeapDumpReceiver extends BroadcastReceiver {
+    private static final String TAG = "HeapDumpReceiver";
+
+    /**
+     * Broadcast action to determine when to delete a specific dump heap. Must include a {@link
+     * HeapDumpActivity#KEY_URI} String extra.
+     */
+    static final String ACTION_DELETE_HEAP_DUMP = "com.android.shell.action.DELETE_HEAP_DUMP";
+
+    /** Broadcast sent when heap dump collection has been completed. */
+    private static final String ACTION_HEAP_DUMP_FINISHED =
+            "com.android.internal.intent.action.HEAP_DUMP_FINISHED";
+
+    /** The process we are reporting */
+    static final String EXTRA_PROCESS_NAME = "com.android.internal.extra.heap_dump.PROCESS_NAME";
+
+    /** The size limit the process reached. */
+    static final String EXTRA_SIZE_BYTES = "com.android.internal.extra.heap_dump.SIZE_BYTES";
+
+    /** Whether the user initiated the dump or not. */
+    static final String EXTRA_IS_USER_INITIATED =
+            "com.android.internal.extra.heap_dump.IS_USER_INITIATED";
+
+    /** Optional name of package to directly launch. */
+    static final String EXTRA_REPORT_PACKAGE =
+            "com.android.internal.extra.heap_dump.REPORT_PACKAGE";
+
+    private static final String NOTIFICATION_CHANNEL_ID = "heapdumps";
+    private static final int NOTIFICATION_ID = 2019;
+
+    /**
+     * Always keep heap dumps taken in the last week.
+     */
+    private static final long MIN_KEEP_AGE_MS = DateUtils.WEEK_IN_MILLIS;
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Log.d(TAG, "onReceive(): " + intent);
+        final String action = intent.getAction();
+        if (action == null) {
+            Log.e(TAG, "null action received");
+            return;
+        }
+        switch (action) {
+            case Intent.ACTION_BOOT_COMPLETED:
+                cleanupOldFiles(context);
+                break;
+            case ACTION_DELETE_HEAP_DUMP:
+                deleteHeapDump(context, intent.getStringExtra(HeapDumpActivity.KEY_URI));
+                break;
+            case ACTION_HEAP_DUMP_FINISHED:
+                showDumpNotification(context, intent);
+                break;
+        }
+    }
+
+    private void cleanupOldFiles(Context context) {
+        final PendingResult result = goAsync();
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                try {
+                    Log.d(TAG, "Deleting from " + new File(context.getFilesDir(), "heapdumps"));
+                    FileUtils.deleteOlderFiles(new File(context.getFilesDir(), "heapdumps"), 0,
+                            MIN_KEEP_AGE_MS);
+                } catch (RuntimeException e) {
+                    Log.e(TAG, "Couldn't delete old files", e);
+                }
+                result.finish();
+                return null;
+            }
+        }.execute();
+    }
+
+    private void deleteHeapDump(Context context, @Nullable final String uri) {
+        if (uri == null) {
+            Log.e(TAG, "null URI for delete heap dump intent");
+            return;
+        }
+        final PendingResult result = goAsync();
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                context.getContentResolver().delete(Uri.parse(uri), null, null);
+                result.finish();
+                return null;
+            }
+        }.execute();
+    }
+
+    private void showDumpNotification(Context context, Intent intent) {
+        final boolean isUserInitiated = intent.getBooleanExtra(
+                EXTRA_IS_USER_INITIATED, false);
+        final String procName = intent.getStringExtra(EXTRA_PROCESS_NAME);
+        final int uid = intent.getIntExtra(Intent.EXTRA_UID, 0);
+
+        final String reportPackage = intent.getStringExtra(
+                EXTRA_REPORT_PACKAGE);
+        final long size = intent.getLongExtra(EXTRA_SIZE_BYTES, 0);
+
+        if (procName == null) {
+            Log.e(TAG, "No process name sent over");
+            return;
+        }
+
+        NotificationManager nm = NotificationManager.from(context);
+        nm.createNotificationChannel(
+                new NotificationChannel(NOTIFICATION_CHANNEL_ID,
+                        "Heap dumps",
+                        NotificationManager.IMPORTANCE_DEFAULT));
+
+        final int titleId = isUserInitiated
+                ? com.android.internal.R.string.dump_heap_ready_notification
+                : com.android.internal.R.string.dump_heap_notification;
+        final String procDisplayName = uid == Process.SYSTEM_UID
+                ? context.getString(com.android.internal.R.string.android_system_label)
+                : procName;
+        String text = context.getString(titleId, procDisplayName);
+
+        Intent shareIntent = new Intent();
+        shareIntent.setClassName(context, HeapDumpActivity.class.getName());
+        shareIntent.putExtra(EXTRA_PROCESS_NAME, procName);
+        shareIntent.putExtra(EXTRA_SIZE_BYTES, size);
+        shareIntent.putExtra(EXTRA_IS_USER_INITIATED, isUserInitiated);
+        shareIntent.putExtra(Intent.EXTRA_UID, uid);
+        if (reportPackage != null) {
+            shareIntent.putExtra(EXTRA_REPORT_PACKAGE, reportPackage);
+        }
+        final Notification.Builder builder = new Notification.Builder(context,
+                NOTIFICATION_CHANNEL_ID)
+                .setSmallIcon(
+                        isTv(context) ? R.drawable.ic_bug_report_black_24dp
+                                : com.android.internal.R.drawable.stat_sys_adb)
+                .setLocalOnly(true)
+                .setColor(context.getColor(
+                        com.android.internal.R.color.system_notification_accent_color))
+                .setContentTitle(text)
+                .setTicker(text)
+                .setAutoCancel(true)
+                .setContentText(context.getText(
+                        com.android.internal.R.string.dump_heap_notification_detail))
+                .setContentIntent(PendingIntent.getActivity(context, 2, shareIntent,
+                        PendingIntent.FLAG_UPDATE_CURRENT));
+
+        Log.v(TAG, "Creating share heap dump notification");
+        NotificationManager.from(context).notify(NOTIFICATION_ID, builder.build());
+    }
+}
diff --git a/packages/SystemUI/README.md b/packages/SystemUI/README.md
index a3d420e..a4dbf38 100644
--- a/packages/SystemUI/README.md
+++ b/packages/SystemUI/README.md
@@ -80,11 +80,6 @@
 
 Creates/initializes the channels sysui uses when posting notifications.
 
-### [com.android.systemui.statusbar.CommandQueue$CommandQueueStart](/packages/SystemUI/src/com/android/systemui/sstatusbar/CommandQueue.java)
-
-Creates CommandQueue and calls putComponent because its always been there
-and sysui expects it to be there :/
-
 ### [com.android.systemui.keyguard.KeyguardViewMediator](/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java)
 
 Manages keyguard view state.
diff --git a/packages/SystemUI/docs/broadcasts.md b/packages/SystemUI/docs/broadcasts.md
new file mode 100644
index 0000000..56a637f
--- /dev/null
+++ b/packages/SystemUI/docs/broadcasts.md
@@ -0,0 +1,89 @@
+# Using SystemUI's BroadcastDispatcher
+
+## What is this dispatcher?
+
+This is an internal dispatcher class for global broadcasts that SystemUI components want to receive. The dispatcher consolidates most `BroadcastReceiver` that exist in SystemUI by merging the `IntentFilter` and subscribing a single `BroadcastReceiver` per user with the system.
+
+## Why use the dispatcher?
+
+Having a single `BroadcastReceiver` in SystemUI improves the multi dispatch situation that occurs whenever many classes are filtering for the same intent action. In particular:
+* All supported `BroadcastReceiver` will be aggregated into one single receiver per user.
+* Whenever there is a broadcast, the number of IPC calls from `system_server` into SystemUI will be reduced to one per user (plus one for `USER_ALL`). This is meaninful for actions that are filtered by `BroadcastReceiver` in multiple classes.
+*There could be more than one per user in the case of unsupported filters.*
+* The dispatcher immediately moves out of the main thread upon broadcast, giving back control to `system_server`. This improves the total dispatch time for broadcasts and prevents from timing out.
+* The dispatcher significantly reduces time spent in main thread by handling most operations in a background thread and only using the main thread for subscribing/unsubscribind and dispatching where appropriate.
+
+## Should I use the dispatcher?
+
+The dispatcher supports `BroadcastReceiver` dynamic subscriptions in the following cases:
+
+* The `IntentFilter` contains at least one action.
+* The `IntentFilter` may or may not contain categories.
+* The `IntentFilter` **does not** contain data types, data schemes, data authorities or data paths.
+* The broadcast **is not** gated behind a permission.
+
+Additionally, the dispatcher supports the following:
+
+* Subscriptions can be done in any thread.
+* Broadcasts will be dispatched on the main thread (same as `system_server`) by default but a `Handler` can be specified for dispatching
+* A `UserHandle` can be provided to filter the broadcasts by user.
+
+If introducing a new `BroadcastReceiver` (not declared in `AndroidManifest`) that satisfies the constraints above, use the dispatcher to reduce the load on `system_server`.
+
+Do not use the dispatcher to obtain the last broadcast (by passing a null `BroadcastReceiver`). `BroadcastDispatcher#registerReceiver` **does not** return the last sticky Intent.
+
+Additionally, if listening to some broadcast is latency critical (beyond 100ms of latency), consider registering with Context instead.
+
+## How do I use the dispatcher?
+
+Acquire the dispatcher by using `@Inject` to obtain a `BroadcastDispatcher`. Then, use the following methods in that instance. 
+
+### Subscribe
+
+```kotlin
+/**
+    * Register a receiver for broadcast with the dispatcher
+    *
+    * @param receiver A receiver to dispatch the [Intent]
+    * @param filter A filter to determine what broadcasts should be dispatched to this receiver.
+    *               It will only take into account actions and categories for filtering. It must
+    *               have at least one action.
+    * @param handler A handler to dispatch [BroadcastReceiver.onReceive]. By default, it is the
+    *                main handler. Pass `null` to use the default.
+    * @param user A user handle to determine which broadcast should be dispatched to this receiver.
+    *             By default, it is the current user.
+    * @throws IllegalArgumentException if the filter has other constraints that are not actions or
+    *                                  categories or the filter has no actions.
+    */
+@JvmOverloads
+fun registerReceiver(BroadcastReceiver, IntentFilter, Handler? = mainHandler, UserHandle = context.user)
+```
+
+All subscriptions are done with the same overloaded method. As specified in the doc, in order to pass a `UserHandle` with the default `Handler`, pass `null` for the `Handler`.
+
+In the same way as with `Context`, subscribing the same `BroadcastReceiver` for the same user using different filters will result on two subscriptions, not in replacing the filter.
+
+### Unsubscribe
+
+There are two methods to unsubscribe a given `BroadcastReceiver`. One that will remove it for all users and another where the user can be specified. This allows using separate subscriptions of the same receiver for different users and manipulating them separately.
+
+```kotlin
+/**
+    * Unregister receiver for all users.
+    * <br>
+    * This will remove every registration of [receiver], not those done just with [UserHandle.ALL].
+    *
+    * @param receiver The receiver to unregister. It will be unregistered for all users.
+    */
+fun unregisterReceiver(BroadcastReceiver)
+
+/**
+    * Unregister receiver for a particular user.
+    *
+    * @param receiver The receiver to unregister. It will be unregistered for all users.
+    * @param user The user associated to the registered [receiver]. It can be [UserHandle.ALL].
+    */
+fun unregisterReceiverForUser(BroadcastReceiver, UserHandle)
+```
+
+Unregistering can be done even if the `BroadcastReceiver` has never been registered with `BroadcastDispatcher`. In that case, it is a No-Op.
diff --git a/packages/SystemUI/plugin/ExamplePlugin/AndroidManifest.xml b/packages/SystemUI/plugin/ExamplePlugin/AndroidManifest.xml
index ff89bbc..e9e8441 100644
--- a/packages/SystemUI/plugin/ExamplePlugin/AndroidManifest.xml
+++ b/packages/SystemUI/plugin/ExamplePlugin/AndroidManifest.xml
@@ -22,14 +22,16 @@
 
     <application>
         <activity android:name=".PluginSettings"
-            android:label="@string/plugin_label">
+                  android:label="@string/plugin_label"
+                  android:exported="false">
             <intent-filter>
                 <action android:name="com.android.systemui.action.PLUGIN_SETTINGS" />
             </intent-filter>
         </activity>
 
         <service android:name=".SampleOverlayPlugin"
-            android:label="@string/plugin_label">
+                 android:label="@string/plugin_label"
+                 android:exported="false">
             <intent-filter>
                 <action android:name="com.android.systemui.action.PLUGIN_OVERLAY" />
             </intent-filter>
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/NotificationPersonExtractorPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/NotificationPersonExtractorPlugin.java
new file mode 100644
index 0000000..6650c15
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/NotificationPersonExtractorPlugin.java
@@ -0,0 +1,81 @@
+/*
+ * 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.plugins;
+
+import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.graphics.drawable.Drawable;
+import android.service.notification.StatusBarNotification;
+
+import com.android.systemui.plugins.annotations.DependsOn;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+/** Custom logic that can extract a PeopleHub "person" from a notification. */
+@ProvidesInterface(
+        action = NotificationPersonExtractorPlugin.ACTION,
+        version = NotificationPersonExtractorPlugin.VERSION)
+@DependsOn(target = NotificationPersonExtractorPlugin.PersonData.class)
+public interface NotificationPersonExtractorPlugin extends Plugin {
+
+    String ACTION = "com.android.systemui.action.PEOPLE_HUB_PERSON_EXTRACTOR";
+    int VERSION = 1;
+
+    /**
+     * Attempts to extract a person from a notification. Returns {@code null} if one is not found.
+     */
+    @Nullable
+    PersonData extractPerson(StatusBarNotification sbn);
+
+    /**
+     * Attempts to extract a person id from a notification. Returns {@code null} if one is not
+     * found.
+     *
+     * This method can be overridden in order to provide a faster implementation.
+     */
+    @Nullable
+    default String extractPersonKey(StatusBarNotification sbn) {
+        return extractPerson(sbn).key;
+    }
+
+    /**
+     * Determines whether or not a notification should be treated as having a person. Used for
+     * appropriate positioning in the notification shade.
+     */
+    default boolean isPersonNotification(StatusBarNotification sbn) {
+        return extractPersonKey(sbn) != null;
+    }
+
+    /** A person to be surfaced in PeopleHub. */
+    @ProvidesInterface(version = PersonData.VERSION)
+    final class PersonData {
+
+        public static final int VERSION = 0;
+
+        public final String key;
+        public final CharSequence name;
+        public final Drawable avatar;
+        public final PendingIntent clickIntent;
+
+        public PersonData(String key, CharSequence name, Drawable avatar,
+                PendingIntent clickIntent) {
+            this.key = key;
+            this.name = name;
+            this.avatar = avatar;
+            this.clickIntent = clickIntent;
+        }
+    }
+}
diff --git a/packages/SystemUI/res/layout/home_controls.xml b/packages/SystemUI/res/layout/home_controls.xml
index bb971c2..69a0e87 100644
--- a/packages/SystemUI/res/layout/home_controls.xml
+++ b/packages/SystemUI/res/layout/home_controls.xml
@@ -1,13 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
+<FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/home_controls_layout"
     android:layout_width="match_parent"
-    android:layout_height="125dp"
+    android:layout_height="wrap_content"
     android:layout_gravity="@integer/notification_panel_layout_gravity"
     android:visibility="gone"
     android:padding="8dp"
     android:layout_margin="5dp"
-    android:background="?android:attr/colorBackgroundFloating"
-    android:orientation="vertical">
-</LinearLayout>
+    android:background="?android:attr/colorBackgroundFloating">
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/people_strip.xml b/packages/SystemUI/res/layout/people_strip.xml
index b314db8..f0ac08b 100644
--- a/packages/SystemUI/res/layout/people_strip.xml
+++ b/packages/SystemUI/res/layout/people_strip.xml
@@ -33,10 +33,9 @@
     <LinearLayout
         android:id="@+id/people_list"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:paddingTop="8dp"
-        android:paddingBottom="8dp"
+        android:layout_height="match_parent"
+        android:paddingTop="12dp"
+        android:paddingBottom="12dp"
         android:gravity="center"
         android:orientation="horizontal">
 
@@ -49,7 +48,7 @@
         <LinearLayout
             android:layout_width="70dp"
             android:layout_height="match_parent"
-            android:gravity="center"
+            android:gravity="center_horizontal"
             android:orientation="vertical"
             android:visibility="invisible">
 
@@ -87,7 +86,7 @@
         <LinearLayout
             android:layout_width="70dp"
             android:layout_height="match_parent"
-            android:gravity="center"
+            android:gravity="center_horizontal"
             android:orientation="vertical"
             android:visibility="invisible">
 
@@ -125,7 +124,7 @@
         <LinearLayout
             android:layout_width="70dp"
             android:layout_height="match_parent"
-            android:gravity="center"
+            android:gravity="center_horizontal"
             android:orientation="vertical"
             android:visibility="invisible">
 
@@ -163,7 +162,7 @@
         <LinearLayout
             android:layout_width="70dp"
             android:layout_height="match_parent"
-            android:gravity="center"
+            android:gravity="center_horizontal"
             android:orientation="vertical"
             android:visibility="invisible">
 
@@ -201,7 +200,7 @@
         <LinearLayout
             android:layout_width="70dp"
             android:layout_height="match_parent"
-            android:gravity="center"
+            android:gravity="center_horizontal"
             android:orientation="vertical"
             android:visibility="invisible">
 
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_plugin_frame.xml b/packages/SystemUI/res/layout/status_bar_expanded_plugin_frame.xml
index 7d6ff3b1..69beffe 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_plugin_frame.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_plugin_frame.xml
@@ -20,7 +20,7 @@
     android:id="@+id/plugin_frame"
     android:theme="@style/qs_theme"
     android:layout_width="@dimen/qs_panel_width"
-    android:layout_height="105dp"
+    android:layout_height="wrap_content"
     android:layout_gravity="center_horizontal"
     android:layout_marginTop="@dimen/notification_side_paddings"
     android:layout_marginLeft="@dimen/notification_side_paddings"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index e86fb70..66a8ade 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Swerwing"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index fed9b05..3f02c95 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5ጂ"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5ጂ+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"በማዛወር ላይ"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"ኤጅ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index b04df54..8c765ac 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"شبكة الجيل الرابع أو أحدث"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+‎"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"‏شبكة 5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"‏شبكة 5G‎ والأحدث"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"التجوال"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"‏شبكة EDGE"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 7efb03c..87be3eb 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -50,8 +50,7 @@
     <string name="usb_device_permission_prompt_warn" msgid="1842558472039505091">"<xliff:g id="APPLICATION">%1$s</xliff:g>ক <xliff:g id="USB_DEVICE">%2$s</xliff:g> এক্সেছ কৰিবলৈ অনুমতি দিবনে?\nএই এপ্‌টোক ৰেকর্ড কৰাৰ অনুমতি দিয়া হোৱা নাই কিন্তু ই এই ইউএছবি ডিভাইচটোৰ জৰিয়তে অডিঅ\' ৰেকর্ড কৰিব পাৰে।"</string>
     <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g>ক <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>ত প্ৰৱেশ কৰিবলৈ অনুমতি দিবনে?"</string>
     <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ক ব্যৱহাৰ কৰিবলৈ <xliff:g id="APPLICATION">%1$s</xliff:g>ক খোলেনে?"</string>
-    <!-- no translation found for usb_device_confirm_prompt_warn (210658281376801521) -->
-    <skip />
+    <string name="usb_device_confirm_prompt_warn" msgid="210658281376801521">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ব্যৱহাৰ কৰিবলৈ <xliff:g id="APPLICATION">%1$s</xliff:g>ক খুলিবনে?\nএই এপ্‌টোক ৰেকর্ড কৰাৰ অনুমতি দিয়া হোৱা নাই কিন্তু ই এই ইউএছবি ডিভাইচটোৰ জৰিয়তে অডিঅ\' ৰেকর্ড কৰিব পাৰে।"</string>
     <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>ক ব্যৱহাৰ কৰিবলৈ <xliff:g id="APPLICATION">%1$s</xliff:g>ক খোলেনে?"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"ইনষ্টল হৈ থকা কোনো এপে ইউএছবি সহায়ক সামগ্ৰীটো চলাব নোৱাৰে। এই সহায়ক সামগ্ৰীৰ বিষয়ে <xliff:g id="URL">%1$s</xliff:g>ৰ জৰিয়তে অধিক জানক৷"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"ইউএছবিৰ সহায়ক সামগ্ৰী"</string>
@@ -189,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"এলটিই"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"এলটিই+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"ৰ\'মিং"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 9d85126..a756ac0 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Rominq"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 07c321d6..a3232e1 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index ec73200..f97d1ec 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Роўмінг"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 6eeae8f..856c020 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Роуминг"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 8e4e9a1..7c3f250f 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"রোমিং"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index c5f94bd..62cb309 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 2ae91dd..18dbd2c 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -50,8 +50,7 @@
     <string name="usb_device_permission_prompt_warn" msgid="1842558472039505091">"Vols permetre que <xliff:g id="APPLICATION">%1$s</xliff:g> accedeixi a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nAquesta aplicació no té permís de gravació, però pot capturar àudio a través d\'aquest dispositiu USB."</string>
     <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Vols permetre que <xliff:g id="APPLICATION">%1$s</xliff:g> accedeixi a <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
     <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Vols obrir <xliff:g id="APPLICATION">%1$s</xliff:g> per gestionar <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
-    <!-- no translation found for usb_device_confirm_prompt_warn (210658281376801521) -->
-    <skip />
+    <string name="usb_device_confirm_prompt_warn" msgid="210658281376801521">"Vols permetre que <xliff:g id="APPLICATION">%1$s</xliff:g> accedeixi a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nAquesta aplicació no té permís de gravació, però pot capturar àudio a través d\'aquest dispositiu USB."</string>
     <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Vols obrir <xliff:g id="APPLICATION">%1$s</xliff:g> per gestionar <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Les aplicacions instal·lades no funcionen amb l\'accessori USB. Més informació: <xliff:g id="URL">%1$s</xliff:g>"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"Accessori USB"</string>
@@ -111,8 +110,8 @@
     <string name="accessibility_phone_button" msgid="6738112589538563574">"Telèfon"</string>
     <string name="accessibility_voice_assist_button" msgid="487611083884852965">"Assistència per veu"</string>
     <string name="accessibility_unlock_button" msgid="128158454631118828">"Desbloqueja"</string>
-    <string name="accessibility_waiting_for_fingerprint" msgid="4808860050517462885">"S\'està esperant l\'empremta dactilar"</string>
-    <string name="accessibility_unlock_without_fingerprint" msgid="7541705575183694446">"Desbloqueja sense utilitzar l\'empremta dactilar"</string>
+    <string name="accessibility_waiting_for_fingerprint" msgid="4808860050517462885">"S\'està esperant l\'empremta digital"</string>
+    <string name="accessibility_unlock_without_fingerprint" msgid="7541705575183694446">"Desbloqueja sense utilitzar l\'empremta digital"</string>
     <string name="accessibility_scanning_face" msgid="769545173211758586">"S\'està escanejant la cara"</string>
     <string name="accessibility_send_smart_reply" msgid="7766727839703044493">"Envia"</string>
     <string name="accessibility_manage_notification" msgid="2026361503393549753">"Gestiona les notificacions"</string>
@@ -137,7 +136,7 @@
     <string name="biometric_dialog_wrong_password" msgid="2343518162282889518">"Contrasenya incorrecta"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="1556206869468265728">"Has superat el nombre d\'intents incorrectes permesos.\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER">%d</xliff:g> segons."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"Toca el sensor d\'empremtes dactilars"</string>
-    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icona d\'empremta dactilar"</string>
+    <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"Icona d\'empremta digital"</string>
     <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"S\'està cercant la teva cara…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"Icona facial"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botó de zoom de compatibilitat."</string>
@@ -189,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Itinerància"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
@@ -536,7 +532,7 @@
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"El dispositiu continuarà bloquejat fins que no el desbloquegis manualment."</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Rep notificacions més ràpidament"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"Mostra-les abans de desbloquejar"</string>
-    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"No"</string>
+    <string name="hidden_notifications_cancel" msgid="3690709735122344913">"No, gràcies"</string>
     <string name="hidden_notifications_setup" msgid="41079514801976810">"Configura"</string>
     <string name="zen_mode_and_condition" msgid="4462471036429759903">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
     <string name="volume_zen_end_now" msgid="6930243045593601084">"Desactiva ara"</string>
@@ -916,7 +912,7 @@
     <string name="slice_permission_deny" msgid="7683681514008048807">"Denega"</string>
     <string name="auto_saver_title" msgid="1217959994732964228">"Toca per programar l\'estalvi de bateria"</string>
     <string name="auto_saver_text" msgid="2563289953551438248">"Activa\'l quan sigui probable que et quedis sense bateria"</string>
-    <string name="no_auto_saver_action" msgid="8086002101711328500">"No"</string>
+    <string name="no_auto_saver_action" msgid="8086002101711328500">"No, gràcies"</string>
     <string name="auto_saver_enabled_title" msgid="6726474226058316862">"S\'ha activat la programació de l\'estalvi de bateria"</string>
     <string name="auto_saver_enabled_text" msgid="874711029884777579">"L\'estalvi de bateria s\'activarà automàticament quan el nivell de bateria sigui inferior al <xliff:g id="PERCENTAGE">%d</xliff:g>%%."</string>
     <string name="open_saver_setting_action" msgid="8314624730997322529">"Configuració"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 916986f..68800f0 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 99fa80e..d3dbc6e 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index aced5d7..15f7876 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 044d396..d30aec9 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Περιαγωγή"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 5bf1b0f..1e50b5a 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index a327151..b2a6e6a 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 5bf1b0f..1e50b5a 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 5bf1b0f..1e50b5a 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 15617b3..568fdb5 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‏‎‏‏‏‏‏‏‎‎‎4G+‎‏‎‎‏‎"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‏‎‎‏‏‎‎‎‏‎‎‎‎‎‎‎‏‎‏‎‏‏‎‏‏‎‎‎‎‏‏‏‎‎‏‎‎‎‎‏‏‎‏‏‏‎‏‏‎‎‎‏‏‎‎LTE‎‏‎‎‏‎"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‎‏‎‎‏‎‏‏‎‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‎‎‏‎‏‎‎‎‎‎LTE+‎‏‎‎‏‎"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‎‏‏‏‏‏‎‏‎‏‏‏‎‎‎‏‎‎‏‏‎5Ge‎‏‎‎‏‎"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‏‎‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‎‎‎‏‎‎‎‎‏‎‏‎‏‏‎‏‏‏‏‏‏‏‏‎‎‎‎5G‎‏‎‎‏‎"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‏‎‎‏‏‏‎‎‏‏‎‏‏‎‎‏‎‎‏‏‏‎‎‏‎‏‎5G+‎‏‎‎‏‎"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‏‎‏‎‎‎‎‎‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‎1X‎‏‎‎‏‎"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‎‏‎‎‎‏‎‎‎‏‏‏‎‏‎‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‏‎‏‎‎‎‎‏‎‎‏‎‏‎‎Roaming‎‏‎‎‏‎"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‎‎‏‏‎‎‏‎‏‏‎‎‎‎‏‏‎‎‎‎‏‎‏‎‏‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‎‎‏‎‏‎‏‎‎EDGE‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index a69de3b..46b402e 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index f96f7b9..d45bf9f 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -50,8 +50,7 @@
     <string name="usb_device_permission_prompt_warn" msgid="1842558472039505091">"¿Quieres que <xliff:g id="APPLICATION">%1$s</xliff:g> pueda acceder a <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEsta aplicación no tiene permisos para grabar, pero podría captar audio a través de este dispositivo USB."</string>
     <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"¿Quieres permitir que <xliff:g id="APPLICATION">%1$s</xliff:g> acceda a <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
     <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"¿Quieres abrir <xliff:g id="APPLICATION">%1$s</xliff:g> para utilizar <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
-    <!-- no translation found for usb_device_confirm_prompt_warn (210658281376801521) -->
-    <skip />
+    <string name="usb_device_confirm_prompt_warn" msgid="210658281376801521">"¿Quieres abrir <xliff:g id="APPLICATION">%1$s</xliff:g> para gestionar <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nEsta aplicación no tiene permisos para grabar, pero puede capturar audio mediante este dispositivo USB."</string>
     <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"¿Quieres abrir <xliff:g id="APPLICATION">%1$s</xliff:g> para utilizar <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Ninguna aplicación instalada funciona con este accesorio USB. Más información: <xliff:g id="URL">%1$s</xliff:g>"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"Accesorio USB"</string>
@@ -189,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5G E"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Itinerancia"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index b106a01..3f7c835 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Rändlus"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 4e9fe245..b6730cf 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -62,7 +62,7 @@
     <string name="usb_debugging_always" msgid="303335496705863070">"Eman beti ordenagailu honetatik arazteko baimena"</string>
     <string name="usb_debugging_allow" msgid="2272145052073254852">"Baimendu"</string>
     <string name="usb_debugging_secondary_user_title" msgid="6353808721761220421">"Ez da onartzen USB arazketa"</string>
-    <string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Gailu honetan saioa hasita duen erabiltzaileak ezin du aktibatu USB arazketa. Eginbide hori erabiltzeko, aldatu erabiltzaile nagusira."</string>
+    <string name="usb_debugging_secondary_user_message" msgid="6067122453571699801">"Gailu honetan saioa hasita daukan erabiltzaileak ezin du aktibatu USB arazketa. Eginbide hori erabiltzeko, aldatu erabiltzaile nagusira."</string>
     <string name="usb_contaminant_title" msgid="206854874263058490">"Desgaitu egin da USB ataka"</string>
     <string name="usb_contaminant_message" msgid="7379089091591609111">"USB ataka desgaitu egin da gailua likido edo zikinkeriengandik babesteko, eta ez du hautemango osagarririk.\n\nJakinarazpen bat jasoko duzu USB ataka berriz erabiltzeko moduan dagoenean."</string>
     <string name="usb_port_enabled" msgid="7906141351687694867">"USB ataka gaitu da kargagailuak eta osagarriak hautemateko"</string>
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Ibiltaritza"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 1751cc9..4f04220 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+‎"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+‎"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"فراگردی"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index c6c90b3..63bc925 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 01427c9..df8b8e4 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Itinérance"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 852bd11..12e06fd0 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Itinérance"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 885302e..85f8cf4 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Itinerancia"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index b3ec665..95d7f41 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"રોમિંગ"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 56117ed..c32ec38 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -50,8 +50,7 @@
     <string name="usb_device_permission_prompt_warn" msgid="1842558472039505091">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> को <xliff:g id="USB_DEVICE">%2$s</xliff:g> ऐक्सेस करने की अनुमति देना चाहते हैं?\nइस ऐप्लिकेशन को रिकॉर्ड करने की अनुमति नहीं दी गई है. हालांकि, ऐप्लिकेशन इस यूएसबी डिवाइस से ऑडियो कैप्चर कर सकता है."</string>
     <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> को <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> के ऐक्सेस की अनुमति दें?"</string>
     <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> के लिए <xliff:g id="APPLICATION">%1$s</xliff:g> खोलें?"</string>
-    <!-- no translation found for usb_device_confirm_prompt_warn (210658281376801521) -->
-    <skip />
+    <string name="usb_device_confirm_prompt_warn" msgid="210658281376801521">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> का इस्तेमाल करने के लिए <xliff:g id="APPLICATION">%1$s</xliff:g> को खोलना चाहते हैं?\n इस ऐप्लिकेशन को रिकॉर्ड करने की अनुमति नहीं दी गई है. हालांकि, ऐप्लिकेशन इस यूएसबी डिवाइस से ऑडियो कैप्चर कर सकता है."</string>
     <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> के लिए <xliff:g id="APPLICATION">%1$s</xliff:g> खोलें?"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"इस USB सहायक डिवाइस के साथ कोई भी इंस्टॉल ऐप्स  काम नहीं करता. इस सहायक डिवाइस के बारे में यहां ज़्यादा जानें: <xliff:g id="URL">%1$s</xliff:g>"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"USB सहायक साधन"</string>
@@ -189,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"एलटीई"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"रोमिंग"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 96b1623..e633878 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G i više"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index bd23d4d..299e318 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Barangolás"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 2647f2f..6291d5d 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Ռոումինգ"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index d0b1045..cf9c4e0 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 8985d27..f98b943 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Reiki"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 68169ab..c08cdd3 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index d059489..fc0c640 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -50,8 +50,7 @@
     <string name="usb_device_permission_prompt_warn" msgid="1842558472039505091">"‏האם לאפשר לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g> גישה אל <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nאפליקציה זו לא קיבלה הרשאה להקליט אך יכולה לתעד אודיו באמצעות מכשיר USB זה."</string>
     <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"האם לתת לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g> גישה אל <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
     <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"האם לפתוח את <xliff:g id="APPLICATION">%1$s</xliff:g> כדי לעבוד עם <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
-    <!-- no translation found for usb_device_confirm_prompt_warn (210658281376801521) -->
-    <skip />
+    <string name="usb_device_confirm_prompt_warn" msgid="210658281376801521">"‏לפתוח את <xliff:g id="APPLICATION">%1$s</xliff:g> לטיפול במכשיר <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nאפליקציה זו לא קיבלה הרשאה להקליט אך יכולה לתעד אודיו באמצעות מכשיר USB זה."</string>
     <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"האם לפתוח את <xliff:g id="APPLICATION">%1$s</xliff:g> כדי לעבוד עם <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"‏אין אפליקציות מותקנות הפועלות עם אביזר ה-USB. למידע נוסף על אביזר זה היכנס לכתובת <xliff:g id="URL">%1$s</xliff:g>"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"‏אביזר USB"</string>
@@ -189,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"+4G"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"+LTE"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"‏+G‏5"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"נדידה"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index e89ae5b..5759e4b 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"ローミング"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 50006dd..8c10ea4 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"როუმინგი"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 05e521c..c646715 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Роуминг"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index a628383..4f87cf1 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"រ៉ូ​មីង"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index dc4674a..f208298 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"ರೋಮಿಂಗ್"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 714af0c..c57d98f 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G 이상"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"로밍"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 820c6b3..b712d62 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Роуминг"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 89d3779..7440be7 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"ໂຣມມິງ"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 208f49b..4a2281d 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5GE"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Tarptinklinis ryšys"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index a96fc3b..2505636 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Viesabonēšana"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index f8dea79..d2eab61 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Роаминг"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 66265cb..ca79e12 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -50,8 +50,7 @@
     <string name="usb_device_permission_prompt_warn" msgid="1842558472039505091">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ആക്‌സസ് ചെയ്യാൻ <xliff:g id="APPLICATION">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കണോ?\nഈ ആപ്പിന് റെക്കോർഡ് അനുമതി നൽകിയിട്ടില്ല, എന്നാൽ ഈ USB ഉപകരണത്തിലൂടെ ഓഡിയോ ക്യാപ്‌ചർ ചെയ്യാനാവും."</string>
     <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ആക്‌സസ് ചെയ്യാൻ <xliff:g id="APPLICATION">%1$s</xliff:g>-നെ അനുവദിക്കണോ?"</string>
     <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> കൈകാര്യം ചെയ്യാൻ <xliff:g id="APPLICATION">%1$s</xliff:g> തുറക്കണോ?"</string>
-    <!-- no translation found for usb_device_confirm_prompt_warn (210658281376801521) -->
-    <skip />
+    <string name="usb_device_confirm_prompt_warn" msgid="210658281376801521">"<xliff:g id="APPLICATION">%1$s</xliff:g> തുറന്ന് <xliff:g id="USB_DEVICE">%2$s</xliff:g> കൈകാര്യം ചെയ്യണോ?\nഈ ആപ്പിന് റെക്കോർഡ് അനുമതി നൽകിയിട്ടില്ല, എന്നാൽ ഈ USB ഉപകരണത്തിലൂടെ ഓഡിയോ ക്യാപ്‌ചർ ചെയ്യാനാവും."</string>
     <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> കൈകാര്യം ചെയ്യാൻ <xliff:g id="APPLICATION">%1$s</xliff:g> തുറക്കണോ?"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"ഈ USB ആക്‌സസ്സറിയിൽ ഇൻസ്‌റ്റാളുചെയ്‌തവയൊന്നും പ്രവർത്തിക്കുന്നില്ല. <xliff:g id="URL">%1$s</xliff:g>-ൽ ഇതേക്കുറിച്ച് കൂടുതലറിയുക"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"USB ആക്‌സസ്സറി"</string>
@@ -189,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"റോമിംഗ്"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDG"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 00e6dcb..50bb578 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Роуминг"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 671060b..7324c51 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -50,8 +50,7 @@
     <string name="usb_device_permission_prompt_warn" msgid="1842558472039505091">"<xliff:g id="APPLICATION">%1$s</xliff:g> ला <xliff:g id="USB_DEVICE">%2$s</xliff:g> अ‍ॅक्सेस करण्याची अनुमती द्यायची का?\nया अ‍ॅपला रेकॉर्ड करण्याची परवानगी दिलेली नाही पण या USB डिव्हाइसद्वारे ऑडिओ कॅप्चर केला जाऊ शकतो."</string>
     <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> ला <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> अ‍ॅक्सेस करण्याची अनुमती द्यायची का?"</string>
     <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> हाताळण्यासाठी <xliff:g id="APPLICATION">%1$s</xliff:g> उघडायचे का?"</string>
-    <!-- no translation found for usb_device_confirm_prompt_warn (210658281376801521) -->
-    <skip />
+    <string name="usb_device_confirm_prompt_warn" msgid="210658281376801521">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> हँडल करण्यासाठी <xliff:g id="APPLICATION">%1$s</xliff:g> उघडायचे आहे का? \n या अ‍ॅपला रेकॉर्ड करण्याची परवानगी दिलेली नाही पण या USB डिव्हाइसद्वारे ऑडिओ कॅप्चर केला जाऊ शकतो."</string>
     <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> हाताळण्यासाठी <xliff:g id="APPLICATION">%1$s</xliff:g> उघडायचे का?"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"इंस्टॉल केलेली अ‍ॅप्स या USB उपसाधनासह कार्य करत नाहीत. <xliff:g id="URL">%1$s</xliff:g> येथे या उपसाधनाविषयी अधिक जाणून घ्या"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"USB उपसाधन"</string>
@@ -189,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"४G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"५Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"१X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"रोमिंग"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 265f161..0faaa5f 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Perayauan"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index c06bb8c..566dc66 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်ခြင်း"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index c213b10..aabdd8b9 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 8006279..ebffa2f 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -50,8 +50,7 @@
     <string name="usb_device_permission_prompt_warn" msgid="1842558472039505091">"<xliff:g id="APPLICATION">%1$s</xliff:g> लाई <xliff:g id="USB_DEVICE">%2$s</xliff:g> माथि पहुँच राख्न अनुमति दिने हो?\nयो अनुप्रयोगलाई रेकर्ड गर्ने अनुमति प्रदान गरिएको छैन तर यसले USB यन्त्रमार्फत अडियो क्याप्चर गर्न सक्छ।"</string>
     <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> लाई <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> माथि पहुँच राख्ने अनुमति दिने हो?"</string>
     <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> को व्यवस्थापन गर्न <xliff:g id="APPLICATION">%1$s</xliff:g> खोल्ने हो?"</string>
-    <!-- no translation found for usb_device_confirm_prompt_warn (210658281376801521) -->
-    <skip />
+    <string name="usb_device_confirm_prompt_warn" msgid="210658281376801521">"<xliff:g id="APPLICATION">%1$s</xliff:g> लाई <xliff:g id="USB_DEVICE">%2$s</xliff:g> सञ्चालन गर्न खोल्ने हो?\nयो अनुप्रयोगलाई रेकर्ड गर्ने अनुमति प्रदान गरिएको छैन तर यसले USB यन्त्रमार्फत अडियो क्याप्चर गर्न सक्छ।"</string>
     <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> को व्यवस्थापन गर्न <xliff:g id="APPLICATION">%1$s</xliff:g> खोल्ने हो?"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"यस USB उपकरणसँग स्थापित अनुप्रयोग काम गर्दैन। यस उपकरणको बारेमा <xliff:g id="URL">%1$s</xliff:g> मा धेरै जान्नुहोस्"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"USB सहयोगी"</string>
@@ -189,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"रोमिङ"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 61e4c33..aa68dce 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5GE"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 527d69f..0985196 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -50,8 +50,7 @@
     <string name="usb_device_permission_prompt_warn" msgid="1842558472039505091">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ଆକ୍ସେସ୍ କରିବାକୁ <xliff:g id="APPLICATION">%1$s</xliff:g>କୁ ଅନୁମତି ଦେବେ କି?\nଏହି ଆପ୍‌କୁ ରେକର୍ଡ କରିବାକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ କିନ୍ତୁ ଏହି USB ଡିଭାଇସ୍ ଜରିଆରେ ଅଡିଓ କ୍ୟାପ୍ଟର୍ କରିପାରିବ।"</string>
     <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ଆକ୍ସେସ୍‍ କରିବାକୁ <xliff:g id="APPLICATION">%1$s</xliff:g>କୁ ଅନୁମତି ଦେବେ?"</string>
     <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ନିୟନ୍ତ୍ରଣ କରିବାକୁ <xliff:g id="APPLICATION">%1$s</xliff:g> ଖୋଲିବେ?"</string>
-    <!-- no translation found for usb_device_confirm_prompt_warn (210658281376801521) -->
-    <skip />
+    <string name="usb_device_confirm_prompt_warn" msgid="210658281376801521">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ପରିଚାଳନା କରିବାକୁ <xliff:g id="APPLICATION">%1$s</xliff:g>କୁ ଖୋଲିବେ?\nଏହି ଆପ୍‌କୁ ରେକର୍ଡ କରିବାକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ କିନ୍ତୁ ଏହି USB ଡିଭାଇସ୍ ଜରିଆରେ, ଏହା ଅଡିଓ କ୍ୟାପ୍ଟର୍ କରିପାରିବ।"</string>
     <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ନିୟନ୍ତ୍ରଣ କରିବାକୁ <xliff:g id="APPLICATION">%1$s</xliff:g> ଖୋଲିବେ?"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"ଇନଷ୍ଟଲ୍‍ ହୋଇଥିବା କୌଣସି ଆପ୍‍ ଏହି USB ଆକ୍ସେସୋରୀରେ କାମ କରେନାହିଁ। ଏହି ଆକ୍ସେସୋରୀ ବିଷୟରେ <xliff:g id="URL">%1$s</xliff:g>ରେ ଅଧିକ ଜାଣନ୍ତୁ"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"USB ଆକ୍ସେସରୀ"</string>
@@ -189,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"ରୋମିଙ୍ଗ"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 18ddddf..cf7f3e9 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -50,8 +50,7 @@
     <string name="usb_device_permission_prompt_warn" msgid="1842558472039505091">"ਕੀ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨੂੰ <xliff:g id="USB_DEVICE">%2$s</xliff:g> ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?\nਇਸ ਐਪ ਨੂੰ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੱਤੀ ਗਈ ਪਰ ਇਹ USB ਡੀਵਾਈਸ ਰਾਹੀਂ ਆਡੀਓ ਕੈਪਚਰ ਕਰ ਸਕਦੀ ਹੈ।"</string>
     <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"ਕੀ <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ਤੱਕ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨੂੰ ਪਹੁੰਚ ਕਰਨ ਦੇਣੀ ਹੈ?"</string>
     <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"ਕੀ <xliff:g id="USB_DEVICE">%2$s</xliff:g> ਨੂੰ ਵਰਤਣ ਲਈ <xliff:g id="APPLICATION">%1$s</xliff:g> ਖੋਲ੍ਹਣੀ ਹੈ?"</string>
-    <!-- no translation found for usb_device_confirm_prompt_warn (210658281376801521) -->
-    <skip />
+    <string name="usb_device_confirm_prompt_warn" msgid="210658281376801521">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ਨੂੰ ਸੰਭਾਲਣ ਲਈ <xliff:g id="APPLICATION">%1$s</xliff:g> ਖੋਲ੍ਹੋ?\nਇਸ ਐਪ ਨੂੰ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੱਤੀ ਗਈ ਪਰ ਇਹ USB ਡੀਵਾਈਸ ਰਾਹੀਂ ਆਡੀਓ ਕੈਪਚਰ ਕਰ ਸਕਦੀ ਹੈ।"</string>
     <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"ਕੀ <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ਨੂੰ ਵਰਤਣ ਲਈ <xliff:g id="APPLICATION">%1$s</xliff:g> ਖੋਲ੍ਹਣੀ ਹੈ?"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"ਕੋਈ ਇੰਸਟੌਲ ਕੀਤੇ ਐਪਸ ਇਸ USB ਐਕਸੈਸਰੀ ਨਾਲ ਕੰਮ ਨਹੀਂ ਕਰਦੇ। <xliff:g id="URL">%1$s</xliff:g> ਤੇ ਇਸ ਐਕਸੈਸਰੀ ਬਾਰੇ ਹੋਰ ਜਾਣੋ"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"USB ਐਕਸੈਸਰੀ"</string>
@@ -189,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"ਰੋਮਿੰਗ"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 44b4112..dc79963 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -188,11 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for data_connection_5ge (4699478963278829331) -->
-    <skip />
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 57d64f5..a9a0309 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 6c80211..ef59a5e 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 57d64f5..a9a0309 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index a6bd29b..a4618d3 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 3459440..9574f0c 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5GE"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Роуминг"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index ab3dc222..2876eb9 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"රෝමිං"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index aa004b4..a969932 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -50,7 +50,7 @@
     <string name="usb_device_permission_prompt_warn" msgid="1842558472039505091">"Povoliť aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g> pristupovať k zariadeniu <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nTejto aplikácii nebolo udelené povolenie na nahrávanie, môže však snímať zvuk cez toto zariadenie USB."</string>
     <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"Povoliť aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g> prístup k zariadeniu <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
     <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"Otvoriť aplikáciu <xliff:g id="APPLICATION">%1$s</xliff:g> na použitie zariadenia <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
-    <string name="usb_device_confirm_prompt_warn" msgid="210658281376801521">"Chcete spracovávať zariadenie <xliff:g id="USB_DEVICE">%2$s</xliff:g> pomocou aplikácie <xliff:g id="APPLICATION">%1$s</xliff:g>?\nTejto aplikácii nebolo udelené povolenie na nahrávanie, ale môže nasnímať zvuk cez toto zariadenie USB."</string>
+    <string name="usb_device_confirm_prompt_warn" msgid="210658281376801521">"Chcete otvoriť aplikáciu <xliff:g id="APPLICATION">%1$s</xliff:g> na správu zariadenia <xliff:g id="USB_DEVICE">%2$s</xliff:g> ?\nTejto aplikácii nebolo udelené povolenie na nahrávanie, ale môže nasnímať zvuk cez toto zariadenie USB."</string>
     <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"Otvoriť aplikáciu <xliff:g id="APPLICATION">%1$s</xliff:g> na použitie zariadenia <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"S týmto zariad. USB nefunguje žiadna nainštal. aplikácia. Ďalšie informácie na <xliff:g id="URL">%1$s</xliff:g>"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"Periférne zariadenie USB"</string>
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 03fa751..9e4045f 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Gostovanje"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 21915c9..6ce621c 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 64ab59b..50775d9 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Роминг"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 0a65cc7..c7fb27c 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5GE"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 48c1fab..12851eb 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Mitandao ya ng\'ambo"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 7263bf6..0d49f27 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"ரோமிங்"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index af330f18f..1600df7 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -50,8 +50,7 @@
     <string name="usb_device_permission_prompt_warn" msgid="1842558472039505091">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>యాక్సెస్ చేయడానికి <xliff:g id="APPLICATION">%1$s</xliff:g>ను అనుమతించాలా?\nఈ యాప్‌నకు రికార్డ్ చేసే అనుమతి మంజూరు చేయబడలేదు, కానీ ఈ USB పరికరం ద్వారా ఆడియోను క్యాప్చర్ చేయగలదు."</string>
     <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>ని యాక్సెస్ చేయడానికి <xliff:g id="APPLICATION">%1$s</xliff:g>ని అనుమతించాలా?"</string>
     <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ని నిర్వహించడానికి <xliff:g id="APPLICATION">%1$s</xliff:g>ని తెరవాలా?"</string>
-    <!-- no translation found for usb_device_confirm_prompt_warn (210658281376801521) -->
-    <skip />
+    <string name="usb_device_confirm_prompt_warn" msgid="210658281376801521">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ని హ్యాండిల్ చేయడానికి <xliff:g id="APPLICATION">%1$s</xliff:g>ను తెరవాలా?\nఈ యాప్‌కు రికార్డ్ చేసే అనుమతి మంజూరు కాలేదు, అయినా ఈ USB పరికరం ద్వారా ఆడియోను క్యాప్చర్ చేయగలదు."</string>
     <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>ని నిర్వహించడానికి <xliff:g id="APPLICATION">%1$s</xliff:g>ని తెరవాలా?"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"ఈ USB ఉపకరణంతో ఇన్‌స్టాల్ చేయబడిన అనువర్తనాలు ఏవీ పని చేయవు. ఈ ఉపకరణం గురించి <xliff:g id="URL">%1$s</xliff:g>లో మరింత తెలుసుకోండి"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"USB ఉపకరణం"</string>
@@ -189,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"రోమింగ్"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index fc062b4..554009e 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5GE"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"โรมมิ่ง"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 37dd49f..309265a 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -102,7 +102,7 @@
     <string name="accessibility_back" msgid="567011538994429120">"Bumalik"</string>
     <string name="accessibility_home" msgid="8217216074895377641">"Home"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menu"</string>
-    <string name="accessibility_accessibility_button" msgid="7601252764577607915">"Pagiging Naa-access"</string>
+    <string name="accessibility_accessibility_button" msgid="7601252764577607915">"Pagiging Accessible"</string>
     <string name="accessibility_rotate_button" msgid="7402949513740253006">"I-rotate ang screen"</string>
     <string name="accessibility_recent" msgid="5208608566793607626">"Overview"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Hanapin"</string>
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Roaming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
@@ -572,7 +569,7 @@
     <string name="stream_notification" msgid="2563720670905665031">"Notification"</string>
     <string name="stream_bluetooth_sco" msgid="2055645746402746292">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="2447177903892477915">"Dual multi tone frequency"</string>
-    <string name="stream_accessibility" msgid="301136219144385106">"Pagiging Naa-access"</string>
+    <string name="stream_accessibility" msgid="301136219144385106">"Pagiging Accessible"</string>
     <string name="ring_toggle_title" msgid="3281244519428819576">"Mga Tawag"</string>
     <string name="volume_ringer_status_normal" msgid="4273142424125855384">"Ipa-ring"</string>
     <string name="volume_ringer_status_vibrate" msgid="1825615171021346557">"I-vibrate"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index c052f4a..f7f4d81 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Dolaşım"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index de6b6f2..39b4deb 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Роумінг"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index b361a4a..aa261da 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -50,8 +50,7 @@
     <string name="usb_device_permission_prompt_warn" msgid="1842558472039505091">"‏<xliff:g id="APPLICATION">%1$s</xliff:g> کو <xliff:g id="USB_DEVICE">%2$s</xliff:g> تک رسائی دیں؟\nاس ایپ کو ریکارڈ کی اجازت عطا نہیں کی گئی ہے مگر اس USB آلہ سے کیپچر کر سکتے ہیں۔"</string>
     <string name="usb_accessory_permission_prompt" msgid="2465531696941369047">"<xliff:g id="APPLICATION">%1$s</xliff:g> کو <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> تک رسائی حاصل کرنے کی اجازت دیں؟"</string>
     <string name="usb_device_confirm_prompt" msgid="7440562274256843905">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ہینڈل کرنے کیلئے <xliff:g id="APPLICATION">%1$s</xliff:g> کھولیں؟"</string>
-    <!-- no translation found for usb_device_confirm_prompt_warn (210658281376801521) -->
-    <skip />
+    <string name="usb_device_confirm_prompt_warn" msgid="210658281376801521">"‏<xliff:g id="USB_DEVICE">%2$s</xliff:g> کو ہینڈل کرنے کے ليے <xliff:g id="APPLICATION">%1$s</xliff:g> کھولیں؟ \nاس ایپ کو ریکارڈ کی اجازت عطا نہیں کی گئی ہے مگر اس USB آلہ سے کیپچر کر سکتے ہیں۔"</string>
     <string name="usb_accessory_confirm_prompt" msgid="4333670517539993561">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ہینڈل کرنے کیلئے <xliff:g id="APPLICATION">%1$s</xliff:g> کھولیں؟"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"‏اس USB لوازم کے ساتھ کوئی انسٹال کردہ ایپس کام نہیں کرتی ہیں۔ <xliff:g id="URL">%1$s</xliff:g> پر مزید جانیں"</string>
     <string name="title_usb_accessory" msgid="4966265263465181372">"‏USB لوازم"</string>
@@ -189,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+‎"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+‎"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+‎"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X‎"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"رومنگ"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 5c077d8..f538853 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Rouming"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 88849c8..78bf627 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G trở lên"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Chuyển vùng"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index cdc2070..de6ad78 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"漫游"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index a69bb7b..0bf6fbf 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5GE"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"漫遊"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index dedaebf..9b3aeb2 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"漫遊"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"EDGE"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 192bfb4..9cf9313 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -188,9 +188,6 @@
     <string name="data_connection_4g_plus" msgid="1148687201877800700">"4G+"</string>
     <string name="data_connection_lte" msgid="2694876797724028614">"I-LTE"</string>
     <string name="data_connection_lte_plus" msgid="3423013208570937424">"I-LTE+"</string>
-    <string name="data_connection_5ge" msgid="4699478963278829331">"5Ge"</string>
-    <string name="data_connection_5g" msgid="6357743323196864504">"5G"</string>
-    <string name="data_connection_5g_plus" msgid="3284146603743732965">"5G+"</string>
     <string name="data_connection_cdma" msgid="8176597308239086780">"1X"</string>
     <string name="data_connection_roaming" msgid="6037232010953697354">"Iyazulazula"</string>
     <string name="data_connection_edge" msgid="871835227939216682">"I-EDGE"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index efcc2c4..dff21cf 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -274,7 +274,6 @@
     <!-- SystemUI Services: The classes of the stuff to start. -->
     <string-array name="config_systemUIServiceComponents" translatable="false">
         <item>com.android.systemui.util.NotificationChannels</item>
-        <item>com.android.systemui.statusbar.CommandQueue$CommandQueueStart</item>
         <item>com.android.systemui.keyguard.KeyguardViewMediator</item>
         <item>com.android.systemui.recents.Recents</item>
         <item>com.android.systemui.volume.VolumeUI</item>
@@ -483,4 +482,7 @@
     <!-- Whether or not to add a "people" notifications section -->
     <bool name="config_usePeopleFiltering">false</bool>
 
+    <!-- Package name for controls plugin -->
+    <string name="config_controlsPluginPackageName" translatable="false">com.android.systemui.controls.panel</string>
+
 </resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 00e8b53..70f8e15 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -78,6 +78,7 @@
 
     // Should match the values in PhoneWindowManager
     public static final String CLOSE_SYSTEM_WINDOWS_REASON_RECENTS = "recentapps";
+    public static final String CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY = "homekey";
 
     private final PackageManager mPackageManager;
     private final BackgroundExecutor mBackgroundExecutor;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
index 6186589..5f92b28 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
@@ -89,6 +89,14 @@
         onTaskMovedToFront(taskInfo.taskId);
     }
 
+    /**
+     * Called when a task’s description is changed due to an activity calling
+     * ActivityManagerService.setTaskDescription
+     *
+     * @param taskInfo info about the task which changed, with {@link TaskInfo#taskDescription}
+     */
+    public void onTaskDescriptionChanged(RunningTaskInfo taskInfo) { }
+
     public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) { }
     public void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken) { }
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index 0c1dbe1..acce41c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -239,6 +239,11 @@
                 .sendToTarget();
     }
 
+    @Override
+    public void onTaskDescriptionChanged(RunningTaskInfo taskInfo) {
+        mHandler.obtainMessage(H.ON_TASK_DESCRIPTION_CHANGED, taskInfo).sendToTarget();
+    }
+
     private final class H extends Handler {
         private static final int ON_TASK_STACK_CHANGED = 1;
         private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
@@ -263,6 +268,7 @@
         private static final int ON_TASK_LIST_UPDATED = 21;
         private static final int ON_SINGLE_TASK_DISPLAY_EMPTY = 22;
         private static final int ON_TASK_LIST_FROZEN_UNFROZEN = 23;
+        private static final int ON_TASK_DESCRIPTION_CHANGED = 24;
 
 
         public H(Looper looper) {
@@ -430,6 +436,13 @@
                         }
                         break;
                     }
+                    case ON_TASK_DESCRIPTION_CHANGED: {
+                        final RunningTaskInfo info = (RunningTaskInfo) msg.obj;
+                        for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                            mTaskStackListeners.get(i).onTaskDescriptionChanged(info);
+                        }
+                        break;
+                    }
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
index 1c30762..ecd8c8d 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
@@ -50,14 +50,6 @@
  * allows the user to return to the call.
  */
 public class EmergencyButton extends Button {
-    private static final Intent INTENT_EMERGENCY_DIAL = new Intent()
-            .setAction(EmergencyDialerConstants.ACTION_DIAL)
-            .setPackage("com.android.phone")
-            .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
-                    | Intent.FLAG_ACTIVITY_CLEAR_TOP)
-            .putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE,
-                    EmergencyDialerConstants.ENTRY_TYPE_LOCKSCREEN_BUTTON);
 
     private static final String LOG_TAG = "EmergencyButton";
     private final EmergencyAffordanceManager mEmergencyAffordanceManager;
@@ -189,7 +181,15 @@
         } else {
             Dependency.get(KeyguardUpdateMonitor.class).reportEmergencyCallAction(
                     true /* bypassHandler */);
-            getContext().startActivityAsUser(INTENT_EMERGENCY_DIAL,
+            Intent emergencyDialIntent =
+                    getTelecommManager().createLaunchEmergencyDialerIntent(null /* number*/)
+                            .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+                                    | Intent.FLAG_ACTIVITY_CLEAR_TOP)
+                            .putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE,
+                                    EmergencyDialerConstants.ENTRY_TYPE_LOCKSCREEN_BUTTON);
+
+            getContext().startActivityAsUser(emergencyDialIntent,
                     ActivityOptions.makeCustomAnimation(getContext(), 0, 0).toBundle(),
                     new UserHandle(KeyguardUpdateMonitor.getCurrentUser()));
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
index 1395fd9..64b4d32 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -75,7 +75,6 @@
             return SecurityMode.SimPin;
         }
 
-        // TODO(b/140034863)
         final int security = whitelistIpcs(() ->
                 mLockPatternUtils.getActivePasswordQuality(userId));
         switch (security) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index 9c0a71c..b1502b9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -104,7 +104,12 @@
 
     private void setLockedSimMessage() {
         boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
-        int count = TelephonyManager.getDefault().getSimCount();
+        int count = 1;
+        TelephonyManager telephonyManager =
+            (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        if (telephonyManager != null) {
+            count = telephonyManager.getActiveModemCount();
+        }
         Resources rez = getResources();
         String msg;
         TypedArray array = mContext.obtainStyledAttributes(new int[] { R.attr.wallpaperTextColor });
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index fc888e1..70237a0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -164,7 +164,12 @@
         }
 
         boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
-        int count = TelephonyManager.getDefault().getSimCount();
+        int count = 1;
+        TelephonyManager telephonyManager =
+            (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        if (telephonyManager != null) {
+            count = telephonyManager.getActiveModemCount();
+        }
         Resources rez = getResources();
         String msg;
         TypedArray array = mContext.obtainStyledAttributes(new int[] { R.attr.wallpaperTextColor });
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 27410be..0b0922a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -99,7 +99,10 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.settingslib.WirelessUtils;
 import com.android.systemui.DejankUtils;
+import com.android.systemui.DumpController;
+import com.android.systemui.Dumpable;
 import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.MainLooper;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.TaskStackChangeListener;
@@ -126,7 +129,7 @@
  * to be updated.
  */
 @Singleton
-public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
+public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpable {
 
     private static final String TAG = "KeyguardUpdateMonitor";
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
@@ -1499,11 +1502,14 @@
 
     @VisibleForTesting
     @Inject
-    protected KeyguardUpdateMonitor(Context context, @MainLooper Looper mainLooper) {
+    protected KeyguardUpdateMonitor(Context context, @MainLooper Looper mainLooper,
+            BroadcastDispatcher broadcastDispatcher,
+            DumpController dumpController) {
         mContext = context;
         mSubscriptionManager = SubscriptionManager.from(context);
         mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
         mStrongAuthTracker = new StrongAuthTracker(context, this::notifyStrongAuthStateChanged);
+        dumpController.registerDumpable(this);
 
         mHandler = new Handler(mainLooper) {
             @Override
@@ -1641,12 +1647,12 @@
         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
-        context.registerReceiver(mBroadcastReceiver, filter, null, mHandler);
+        broadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, mHandler);
 
         final IntentFilter bootCompleteFilter = new IntentFilter();
         bootCompleteFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
         bootCompleteFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
-        context.registerReceiver(mBroadcastReceiver, bootCompleteFilter, null, mHandler);
+        broadcastDispatcher.registerReceiver(mBroadcastReceiver, bootCompleteFilter, mHandler);
 
         final IntentFilter allUserFilter = new IntentFilter();
         allUserFilter.addAction(Intent.ACTION_USER_INFO_CHANGED);
@@ -1657,8 +1663,8 @@
         allUserFilter.addAction(ACTION_USER_UNLOCKED);
         allUserFilter.addAction(ACTION_USER_STOPPED);
         allUserFilter.addAction(ACTION_USER_REMOVED);
-        context.registerReceiverAsUser(mBroadcastAllReceiver, UserHandle.ALL, allUserFilter,
-                null, mHandler);
+        broadcastDispatcher.registerReceiver(mBroadcastAllReceiver, allUserFilter, mHandler,
+                UserHandle.ALL);
 
         mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);
         try {
@@ -2643,8 +2649,10 @@
         // that don't return the complete set of values and have different types. In Keyguard we
         // need IccCardConstants, but TelephonyManager would only give us
         // TelephonyManager.SIM_STATE*, so we retrieve it manually.
-        final TelephonyManager tele = TelephonyManager.from(mContext);
-        int simState = tele.getSimState(slotId);
+        final TelephonyManager tele =
+            (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        int simState = (tele != null) ?
+            tele.getSimState(slotId) : TelephonyManager.SIM_STATE_UNKNOWN;
         State state;
         try {
             state = State.intToState(simState);
@@ -2787,6 +2795,7 @@
         }
     }
 
+    @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("KeyguardUpdateMonitor state:");
         pw.println("  SIM States:");
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index 9e2464e..dfabe69 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -32,6 +32,7 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.lifecycle.Observer;
 
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dock.DockManager.DockEventListener;
@@ -125,9 +126,9 @@
     @Inject
     public ClockManager(Context context, InjectionInflationController injectionInflater,
             PluginManager pluginManager, SysuiColorExtractor colorExtractor,
-            @Nullable DockManager dockManager) {
+            @Nullable DockManager dockManager, BroadcastDispatcher broadcastDispatcher) {
         this(context, injectionInflater, pluginManager, colorExtractor,
-                context.getContentResolver(), new CurrentUserObservable(context),
+                context.getContentResolver(), new CurrentUserObservable(broadcastDispatcher),
                 new SettingsWrapper(context.getContentResolver()), dockManager);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index ce61a00..2afcb12 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -51,9 +51,11 @@
 
 import com.android.settingslib.Utils;
 import com.android.settingslib.graph.ThemedBatteryDrawable;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.settings.CurrentUserTracker;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
@@ -111,16 +113,13 @@
     private int mNonAdaptedForegroundColor;
     private int mNonAdaptedBackgroundColor;
 
-    public BatteryMeterView(Context context) {
-        this(context, null, 0);
-    }
-
     public BatteryMeterView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
     public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+        BroadcastDispatcher broadcastDispatcher = Dependency.get(BroadcastDispatcher.class);
 
         setOrientation(LinearLayout.HORIZONTAL);
         setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
@@ -139,7 +138,8 @@
 
 
         addOnAttachStateChangeListener(
-                new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS));
+                new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS,
+                        Dependency.get(CommandQueue.class)));
 
         setupLayoutTransition();
 
@@ -159,7 +159,7 @@
         // Init to not dark at all.
         onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
 
-        mUserTracker = new CurrentUserTracker(mContext) {
+        mUserTracker = new CurrentUserTracker(broadcastDispatcher) {
             @Override
             public void onUserSwitched(int newUserId) {
                 mUser = newUserId;
diff --git a/packages/SystemUI/src/com/android/systemui/CornerHandleView.java b/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
index a94952c..8e472f9 100644
--- a/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
+++ b/packages/SystemUI/src/com/android/systemui/CornerHandleView.java
@@ -47,6 +47,7 @@
     private int mLightColor;
     private int mDarkColor;
     private Path mPath;
+    private boolean mRequiresInvalidate;
 
     public CornerHandleView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -67,6 +68,15 @@
         updatePath();
     }
 
+    @Override
+    public void setAlpha(float alpha) {
+        super.setAlpha(alpha);
+        if (alpha > 0f && mRequiresInvalidate) {
+            mRequiresInvalidate = false;
+            invalidate();
+        }
+    }
+
     private void updatePath() {
         mPath = new Path();
 
@@ -104,11 +114,16 @@
      * appropriately. Intention is to match the home handle color.
      */
     public void updateDarkness(float darkIntensity) {
-        mPaint.setColor((int) ArgbEvaluator.getInstance().evaluate(darkIntensity,
-                mLightColor,
-                mDarkColor));
-        if (getVisibility() == VISIBLE) {
-            invalidate();
+        int color = (int) ArgbEvaluator.getInstance().evaluate(darkIntensity,
+                mLightColor, mDarkColor);
+        if (mPaint.getColor() != color) {
+            mPaint.setColor(color);
+            if (getVisibility() == VISIBLE && getAlpha() > 0) {
+                invalidate();
+            } else {
+                // If we are currently invisible, then invalidate when we are next made visible
+                mRequiresInvalidate = true;
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 486d02c..b3f32af 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -63,6 +63,7 @@
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
 import com.android.systemui.shared.system.PackageManagerWrapper;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NavigationBarController;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -326,6 +327,7 @@
     @Inject Lazy<KeyguardSecurityModel> mKeyguardSecurityModel;
     @Inject Lazy<DozeParameters> mDozeParameters;
     @Inject Lazy<IWallpaperManager> mWallpaperManager;
+    @Inject Lazy<CommandQueue> mCommandQueue;
 
     @Inject
     public Dependency() {
@@ -514,6 +516,7 @@
         mProviders.put(KeyguardSecurityModel.class, mKeyguardSecurityModel::get);
         mProviders.put(DozeParameters.class, mDozeParameters::get);
         mProviders.put(IWallpaperManager.class, mWallpaperManager::get);
+        mProviders.put(CommandQueue.class, mCommandQueue::get);
 
         // TODO(b/118592525): to support multi-display , we start to add something which is
         //                    per-display, while others may be global. I think it's time to add
diff --git a/packages/SystemUI/src/com/android/systemui/DumpController.kt b/packages/SystemUI/src/com/android/systemui/DumpController.kt
index 65f1abd..8c7075b 100644
--- a/packages/SystemUI/src/com/android/systemui/DumpController.kt
+++ b/packages/SystemUI/src/com/android/systemui/DumpController.kt
@@ -47,6 +47,16 @@
     /**
      * Adds a [Dumpable] dumpable to be dumped.
      *
+     * @param dumpable the [Dumpable] to be added
+     */
+    fun registerDumpable(dumpable: Dumpable) {
+        Preconditions.checkNotNull(dumpable, "The dumpable to be added cannot be null")
+        registerDumpable(dumpable.javaClass.simpleName, dumpable)
+    }
+
+    /**
+     * Adds a [Dumpable] dumpable to be dumped.
+     *
      * @param tag a string tag to associate with this dumpable. Tags must be globally unique; this
      *      method will throw if the same tag has already been registered. Tags can be used to
      *      filter output when debugging.
@@ -79,11 +89,11 @@
     /**
      * Dump all the [Dumpable] registered with the controller
      */
-    override fun dump(fd: FileDescriptor?, pw: PrintWriter, args: Array<String>?) {
+    override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
         pw.println("DumpController state:")
 
-        val filter = if (args != null && args.size >= 3 &&
-                args[0] == "dependency" && args[1] == "DumpController") {
+        val filter = if (args.size >= 3 && args[0].toLowerCase() == "dependency" &&
+                args[1] == "DumpController") {
             ArraySet(args[2].split(',').map { it.toLowerCase() })
         } else {
             null
diff --git a/packages/SystemUI/src/com/android/systemui/Dumpable.java b/packages/SystemUI/src/com/android/systemui/Dumpable.java
index 65a6844..10a0643 100644
--- a/packages/SystemUI/src/com/android/systemui/Dumpable.java
+++ b/packages/SystemUI/src/com/android/systemui/Dumpable.java
@@ -14,9 +14,24 @@
 
 package com.android.systemui;
 
+import androidx.annotation.NonNull;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
+/**
+ * Implemented by classes who want to be in:
+ *   {@code adb shell dumpsys activity service com.android.systemui}
+ *
+ * @see DumpController
+ */
 public interface Dumpable {
-    void dump(FileDescriptor fd, PrintWriter pw, String[] args);
+
+    /**
+     * Called when it's time to dump the internal state
+     * @param fd A file descriptor.
+     * @param pw Where to write your dump to.
+     * @param args Arguments.
+     */
+    void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
index df0d787..795a8ce3 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
@@ -21,10 +21,13 @@
 import android.util.SparseArray;
 
 import com.android.internal.messages.nano.SystemMessageProto;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
+
 /**
  * Tracks state of foreground services and notifications related to foreground services per user.
  */
@@ -33,9 +36,11 @@
 
     private final SparseArray<ForegroundServicesUserState> mUserServices = new SparseArray<>();
     private final Object mMutex = new Object();
+    private final NotificationEntryManager mEntryManager;
 
     @Inject
-    public ForegroundServiceController() {
+    public ForegroundServiceController(NotificationEntryManager entryManager) {
+        mEntryManager = entryManager;
     }
 
     /**
@@ -90,11 +95,18 @@
     }
 
     /**
-     * Records active app ops. App Ops are stored in FSC in addition to NotificationData in
-     * case they change before we have a notification to tag.
+     * Records active app ops and updates the app op for the pending or visible notifications
+     * with the given parameters.
+     * App Ops are stored in FSC in addition to NotificationEntry in case they change before we
+     * have a notification to tag.
+     * @param appOpCode code for appOp to add/remove
+     * @param uid of user the notification is sent to
+     * @param packageName package that created the notification
+     * @param active whether the appOpCode is active or not
      */
-    public void onAppOpChanged(int code, int uid, String packageName, boolean active) {
+    public void onAppOpChanged(int appOpCode, int uid, String packageName, boolean active) {
         int userId = UserHandle.getUserId(uid);
+        // Record active app ops
         synchronized (mMutex) {
             ForegroundServicesUserState userServices = mUserServices.get(userId);
             if (userServices == null) {
@@ -102,9 +114,30 @@
                 mUserServices.put(userId, userServices);
             }
             if (active) {
-                userServices.addOp(packageName, code);
+                userServices.addOp(packageName, appOpCode);
             } else {
-                userServices.removeOp(packageName, code);
+                userServices.removeOp(packageName, appOpCode);
+            }
+        }
+
+        // Update appOp if there's an associated pending or visible notification:
+        final String foregroundKey = getStandardLayoutKey(userId, packageName);
+        if (foregroundKey != null) {
+            final NotificationEntry entry = mEntryManager.getPendingOrCurrentNotif(foregroundKey);
+            if (entry != null
+                    && uid == entry.getSbn().getUid()
+                    && packageName.equals(entry.getSbn().getPackageName())) {
+                boolean changed;
+                synchronized (entry.mActiveAppOps) {
+                    if (active) {
+                        changed = entry.mActiveAppOps.add(appOpCode);
+                    } else {
+                        changed = entry.mActiveAppOps.remove(appOpCode);
+                    }
+                }
+                if (changed) {
+                    mEntryManager.updateNotifications("appOpChanged pkg=" + packageName);
+                }
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
index 4a3b6df..b983966 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.os.Bundle;
 import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
 import android.util.Log;
 
 import com.android.internal.statusbar.NotificationVisibility;
@@ -40,6 +41,7 @@
 
     private final Context mContext;
     private final ForegroundServiceController mForegroundServiceController;
+    private final NotificationEntryManager mEntryManager;
 
     @Inject
     public ForegroundServiceNotificationListener(Context context,
@@ -47,15 +49,16 @@
             NotificationEntryManager notificationEntryManager) {
         mContext = context;
         mForegroundServiceController = foregroundServiceController;
-        notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
+        mEntryManager = notificationEntryManager;
+        mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
             public void onPendingEntryAdded(NotificationEntry entry) {
-                addNotification(entry.getSbn(), entry.getImportance());
+                addNotification(entry, entry.getImportance());
             }
 
             @Override
-            public void onPostEntryUpdated(NotificationEntry entry) {
-                updateNotification(entry.getSbn(), entry.getImportance());
+            public void onPreEntryUpdated(NotificationEntry entry) {
+                updateNotification(entry, entry.getImportance());
             }
 
             @Override
@@ -67,15 +70,14 @@
             }
         });
 
-        notificationEntryManager.addNotificationLifetimeExtender(
-                new ForegroundServiceLifetimeExtender());
+        mEntryManager.addNotificationLifetimeExtender(new ForegroundServiceLifetimeExtender());
     }
 
     /**
-     * @param sbn notification that was just posted
+     * @param entry notification that was just posted
      */
-    private void addNotification(StatusBarNotification sbn, int importance) {
-        updateNotification(sbn, importance);
+    private void addNotification(NotificationEntry entry, int importance) {
+        updateNotification(entry, importance);
     }
 
     /**
@@ -113,9 +115,10 @@
     }
 
     /**
-     * @param sbn notification that was just changed in some way
+     * @param entry notification that was just changed in some way
      */
-    private void updateNotification(StatusBarNotification sbn, int newImportance) {
+    private void updateNotification(NotificationEntry entry, int newImportance) {
+        final StatusBarNotification sbn = entry.getSbn();
         mForegroundServiceController.updateUserState(
                 sbn.getUserId(),
                 userState -> {
@@ -143,8 +146,22 @@
                             }
                         }
                     }
+                    tagForeground(entry);
                     return true;
                 },
                 true /* create if not found */);
     }
+
+    private void tagForeground(NotificationEntry entry) {
+        final StatusBarNotification sbn = entry.getSbn();
+        ArraySet<Integer> activeOps = mForegroundServiceController.getAppOps(
+                sbn.getUserId(),
+                sbn.getPackageName());
+        if (activeOps != null) {
+            synchronized (entry.mActiveAppOps) {
+                entry.mActiveAppOps.clear();
+                entry.mActiveAppOps.addAll(activeOps);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
index 3a8536b..4afa969 100644
--- a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
@@ -32,6 +32,7 @@
 import android.util.Log;
 import android.view.WindowManagerGlobal;
 
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 
 /**
@@ -45,10 +46,14 @@
 
     private Dialog mNewSessionDialog;
 
-    public void register(Context context) {
+    /**
+     * Register this receiver with the {@link BroadcastDispatcher}
+     *
+     * @param broadcastDispatcher to register the receiver.
+     */
+    public void register(BroadcastDispatcher broadcastDispatcher) {
         IntentFilter f = new IntentFilter(Intent.ACTION_USER_SWITCHED);
-        context.registerReceiverAsUser(this, UserHandle.SYSTEM,
-                f, null /* permission */, null /* scheduler */);
+        broadcastDispatcher.registerReceiver(this, f, null /* handler */, UserHandle.SYSTEM);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/LatencyTester.java b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
index ddbabee..1a47dac 100644
--- a/packages/SystemUI/src/com/android/systemui/LatencyTester.java
+++ b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui;
 
+import static android.os.PowerManager.WAKE_REASON_UNKNOWN;
+
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -27,22 +29,37 @@
 
 import com.android.internal.util.LatencyTracker;
 import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.statusbar.phone.BiometricUnlockController;
-import com.android.systemui.statusbar.phone.StatusBar;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
 
 /**
  * Class that only runs on debuggable builds that listens to broadcasts that simulate actions in the
  * system that are used for testing the latency.
  */
+@Singleton
 public class LatencyTester extends SystemUI {
 
-    private static final String ACTION_FINGERPRINT_WAKE =
+    private static final String
+            ACTION_FINGERPRINT_WAKE =
             "com.android.systemui.latency.ACTION_FINGERPRINT_WAKE";
-    private static final String ACTION_TURN_ON_SCREEN =
+    private static final String
+            ACTION_TURN_ON_SCREEN =
             "com.android.systemui.latency.ACTION_TURN_ON_SCREEN";
+    private final BiometricUnlockController mBiometricUnlockController;
+    private final PowerManager mPowerManager;
+    private final BroadcastDispatcher mBroadcastDispatcher;
 
-    public LatencyTester(Context context) {
+    @Inject
+    public LatencyTester(Context context, BiometricUnlockController biometricUnlockController,
+            PowerManager powerManager, BroadcastDispatcher broadcastDispatcher) {
         super(context);
+
+        mBiometricUnlockController = biometricUnlockController;
+        mPowerManager = powerManager;
+        mBroadcastDispatcher = broadcastDispatcher;
     }
 
     @Override
@@ -54,7 +71,7 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(ACTION_FINGERPRINT_WAKE);
         filter.addAction(ACTION_TURN_ON_SCREEN);
-        mContext.registerReceiver(new BroadcastReceiver() {
+        mBroadcastDispatcher.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
                 String action = intent.getAction();
@@ -68,19 +85,17 @@
     }
 
     private void fakeTurnOnScreen() {
-        PowerManager powerManager = mContext.getSystemService(PowerManager.class);
         if (LatencyTracker.isEnabled(mContext)) {
             LatencyTracker.getInstance(mContext).onActionStart(
                     LatencyTracker.ACTION_TURN_ON_SCREEN);
         }
-        powerManager.wakeUp(SystemClock.uptimeMillis(), "android.policy:LATENCY_TESTS");
+        mPowerManager.wakeUp(
+                SystemClock.uptimeMillis(), WAKE_REASON_UNKNOWN, "android.policy:LATENCY_TESTS");
     }
 
     private void fakeWakeAndUnlock() {
-        BiometricUnlockController biometricUnlockController = getComponent(StatusBar.class)
-                .getBiometricUnlockController();
-        biometricUnlockController.onBiometricAcquired(BiometricSourceType.FINGERPRINT);
-        biometricUnlockController.onBiometricAuthenticated(
+        mBiometricUnlockController.onBiometricAcquired(BiometricSourceType.FINGERPRINT);
+        mBiometricUnlockController.onBiometricAuthenticated(
                 KeyguardUpdateMonitor.getCurrentUser(), BiometricSourceType.FINGERPRINT);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index ad20986..ab7eec5 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -67,6 +67,8 @@
 
 import com.android.internal.util.Preconditions;
 import com.android.systemui.RegionInterceptingFrameLayout.RegionInterceptableView;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.MainHandler;
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
 import com.android.systemui.plugins.qs.QS;
@@ -81,10 +83,16 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import dagger.Lazy;
+
 /**
  * An overlay that draws screen decorations in software (e.g for rounded corners or display cutout)
  * for antialiasing and emulation purposes.
  */
+@Singleton
 public class ScreenDecorations extends SystemUI implements Tunable {
     private static final boolean DEBUG = false;
     private static final String TAG = "ScreenDecorations";
@@ -94,8 +102,12 @@
     private static final boolean DEBUG_SCREENSHOT_ROUNDED_CORNERS =
             SystemProperties.getBoolean("debug.screenshot_rounded_corners", false);
     private static final boolean VERBOSE = false;
+    private final Lazy<StatusBar> mStatusBarLazy;
 
     private DisplayManager mDisplayManager;
+    private final BroadcastDispatcher mBroadcastDispatcher;
+    private final Handler mMainHandler;
+    private final TunerService mTunerService;
     private DisplayManager.DisplayListener mDisplayListener;
 
     @VisibleForTesting
@@ -132,8 +144,17 @@
         return result;
     }
 
-    public ScreenDecorations(Context context) {
+    @Inject
+    public ScreenDecorations(Context context,
+            Lazy<StatusBar> statusBarLazy,
+            @MainHandler Handler handler,
+            BroadcastDispatcher broadcastDispatcher,
+            TunerService tunerService) {
         super(context);
+        mStatusBarLazy = statusBarLazy;
+        mMainHandler = handler;
+        mBroadcastDispatcher = broadcastDispatcher;
+        mTunerService = tunerService;
     }
 
     @Override
@@ -230,8 +251,7 @@
         mWindowManager.getDefaultDisplay().getMetrics(metrics);
         mDensity = metrics.density;
 
-        Dependency.get(Dependency.MAIN_HANDLER).post(
-                () -> Dependency.get(TunerService.class).addTunable(this, SIZE));
+        mMainHandler.post(() -> mTunerService.addTunable(this, SIZE));
 
         // Watch color inversion and invert the overlay as needed.
         mColorInversionSetting = new SecureSetting(mContext, mHandler,
@@ -246,7 +266,7 @@
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_SWITCHED);
-        mContext.registerReceiver(mIntentReceiver, filter, null /* permission */, mHandler);
+        mBroadcastDispatcher.registerReceiver(mIntentReceiver, filter, mHandler);
 
         mOverlay.addOnLayoutChangeListener(new OnLayoutChangeListener() {
             @Override
@@ -434,13 +454,13 @@
 
     private void setupStatusBarPadding(int padding) {
         // Add some padding to all the content near the edge of the screen.
-        StatusBar sb = getComponent(StatusBar.class);
-        View statusBar = (sb != null ? sb.getStatusBarWindow() : null);
-        if (statusBar != null) {
-            TunablePadding.addTunablePadding(statusBar.findViewById(R.id.keyguard_header), PADDING,
-                    padding, FLAG_END);
+        StatusBar statusBar = mStatusBarLazy.get();
+        View statusBarWindow = statusBar.getStatusBarWindow();
+        if (statusBarWindow != null) {
+            TunablePadding.addTunablePadding(statusBarWindow.findViewById(R.id.keyguard_header),
+                    PADDING, padding, FLAG_END);
 
-            FragmentHostManager fragmentHostManager = FragmentHostManager.get(statusBar);
+            FragmentHostManager fragmentHostManager = FragmentHostManager.get(statusBarWindow);
             fragmentHostManager.addTagListener(CollapsedStatusBarFragment.TAG,
                     new TunablePaddingTagListener(padding, R.id.status_bar));
             fragmentHostManager.addTagListener(QS.TAG,
diff --git a/packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java b/packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java
index 10009f5..72a4030 100644
--- a/packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/SizeCompatModeActivityController.java
@@ -47,7 +47,11 @@
 
 import java.lang.ref.WeakReference;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
 /** Shows a restart-activity button when the foreground activity is in size compatibility mode. */
+@Singleton
 public class SizeCompatModeActivityController extends SystemUI implements CommandQueue.Callbacks {
     private static final String TAG = "SizeCompatMode";
 
@@ -55,17 +59,17 @@
     private final SparseArray<RestartActivityButton> mActiveButtons = new SparseArray<>(1);
     /** Avoid creating display context frequently for non-default display. */
     private final SparseArray<WeakReference<Context>> mDisplayContextCache = new SparseArray<>(0);
+    private final CommandQueue mCommandQueue;
 
     /** Only show once automatically in the process life. */
     private boolean mHasShownHint;
 
-    public SizeCompatModeActivityController(Context context) {
-        this(context, ActivityManagerWrapper.getInstance());
-    }
-
     @VisibleForTesting
-    SizeCompatModeActivityController(Context context, ActivityManagerWrapper am) {
+    @Inject
+    SizeCompatModeActivityController(Context context, ActivityManagerWrapper am,
+            CommandQueue commandQueue) {
         super(context);
+        mCommandQueue = commandQueue;
         am.registerTaskStackListener(new TaskStackChangeListener() {
             @Override
             public void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken) {
@@ -77,7 +81,7 @@
 
     @Override
     public void start() {
-        SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallback(this);
+        mCommandQueue.addCallback(this);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/SliceBroadcastRelayHandler.java b/packages/SystemUI/src/com/android/systemui/SliceBroadcastRelayHandler.java
index 92fbd25..7a4ef2b 100644
--- a/packages/SystemUI/src/com/android/systemui/SliceBroadcastRelayHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/SliceBroadcastRelayHandler.java
@@ -28,19 +28,27 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.SliceBroadcastRelay;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
 
 /**
  * Allows settings to register certain broadcasts to launch the settings app for pinned slices.
  * @see SliceBroadcastRelay
  */
+@Singleton
 public class SliceBroadcastRelayHandler extends SystemUI {
     private static final String TAG = "SliceBroadcastRelay";
     private static final boolean DEBUG = false;
 
     private final ArrayMap<Uri, BroadcastRelay> mRelays = new ArrayMap<>();
+    private final BroadcastDispatcher mBroadcastDispatcher;
 
-    public SliceBroadcastRelayHandler(Context context) {
+    @Inject
+    public SliceBroadcastRelayHandler(Context context, BroadcastDispatcher broadcastDispatcher) {
         super(context);
+        mBroadcastDispatcher = broadcastDispatcher;
     }
 
     @Override
@@ -48,9 +56,10 @@
         if (DEBUG) Log.d(TAG, "Start");
         IntentFilter filter = new IntentFilter(SliceBroadcastRelay.ACTION_REGISTER);
         filter.addAction(SliceBroadcastRelay.ACTION_UNREGISTER);
-        mContext.registerReceiver(mReceiver, filter);
+        mBroadcastDispatcher.registerReceiver(mReceiver, filter);
     }
 
+    // This does not use BroadcastDispatcher as the filter may have schemas or mime types.
     @VisibleForTesting
     void handleIntent(Intent intent) {
         if (SliceBroadcastRelay.ACTION_REGISTER.equals(intent.getAction())) {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java
index 746515a..cacbf96 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java
@@ -19,6 +19,7 @@
 import android.app.Activity;
 import android.app.Application;
 import android.app.Service;
+import android.content.BroadcastReceiver;
 import android.content.ContentProvider;
 import android.content.Context;
 import android.content.Intent;
@@ -125,6 +126,25 @@
         return super.instantiateServiceCompat(cl, className, intent);
     }
 
+    @NonNull
+    @Override
+    public BroadcastReceiver instantiateReceiverCompat(@NonNull ClassLoader cl,
+            @NonNull String className, @Nullable Intent intent)
+            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+        if (mComponentHelper == null) {
+            // This shouldn't happen, but does when a device is freshly formatted.
+            // Bug filed against framework to take a look: http://b/141008541
+            SystemUIFactory.getInstance().getRootComponent().inject(
+                    SystemUIAppComponentFactory.this);
+        }
+        BroadcastReceiver receiver = mComponentHelper.resolveBroadcastReceiver(className);
+        if (receiver != null) {
+            return receiver;
+        }
+
+        return super.instantiateReceiverCompat(cl, className, intent);
+    }
+
     /**
      * A callback that receives a Context when one is ready.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 022bf06..aab4041 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -24,23 +24,14 @@
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
-import android.os.Handler;
-import android.os.Looper;
 import android.os.Process;
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
-import android.util.ArraySet;
 import android.util.Log;
 import android.util.TimingsTraceLog;
 
 import com.android.systemui.dagger.ContextComponentHelper;
-import com.android.systemui.plugins.OverlayPlugin;
-import com.android.systemui.plugins.PluginListener;
-import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.phone.StatusBarWindowController;
 import com.android.systemui.util.NotificationChannels;
 
 import java.lang.reflect.Constructor;
@@ -224,65 +215,6 @@
         }
         Dependency.get(InitController.class).executePostInitTasks();
         log.traceEnd();
-        final Handler mainHandler = new Handler(Looper.getMainLooper());
-        Dependency.get(PluginManager.class).addPluginListener(
-                new PluginListener<OverlayPlugin>() {
-                    private ArraySet<OverlayPlugin> mOverlays = new ArraySet<>();
-
-                    @Override
-                    public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
-                        mainHandler.post(new Runnable() {
-                            @Override
-                            public void run() {
-                                StatusBar statusBar = getComponent(StatusBar.class);
-                                if (statusBar != null) {
-                                    plugin.setup(statusBar.getStatusBarWindow(),
-                                            statusBar.getNavigationBarView(), new Callback(plugin),
-                                            Dependency.get(DozeParameters.class));
-                                }
-                            }
-                        });
-                    }
-
-                    @Override
-                    public void onPluginDisconnected(OverlayPlugin plugin) {
-                        mainHandler.post(new Runnable() {
-                            @Override
-                            public void run() {
-                                mOverlays.remove(plugin);
-                                Dependency.get(StatusBarWindowController.class).setForcePluginOpen(
-                                        mOverlays.size() != 0);
-                            }
-                        });
-                    }
-
-                    class Callback implements OverlayPlugin.Callback {
-                        private final OverlayPlugin mPlugin;
-
-                        Callback(OverlayPlugin plugin) {
-                            mPlugin = plugin;
-                        }
-
-                        @Override
-                        public void onHoldStatusBarOpenChange() {
-                            if (mPlugin.holdStatusBarOpen()) {
-                                mOverlays.add(mPlugin);
-                            } else {
-                                mOverlays.remove(mPlugin);
-                            }
-                            mainHandler.post(new Runnable() {
-                                @Override
-                                public void run() {
-                                    Dependency.get(StatusBarWindowController.class)
-                                            .setStateListener(b -> mOverlays.forEach(
-                                                    o -> o.setCollapseDesired(b)));
-                                    Dependency.get(StatusBarWindowController.class)
-                                            .setForcePluginOpen(mOverlays.size() != 0);
-                                }
-                            });
-                        }
-                    }
-                }, OverlayPlugin.class, true /* Allow multiple plugins */);
 
         mServicesStarted = true;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index 3f56ff0..8825f12 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -67,13 +67,11 @@
 
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (args != null && args.length > 0 && args[0].equals("--config")) {
-            dumpConfig(pw);
-            return;
-        }
-
         dumpServices(((SystemUIApplication) getApplication()).getServices(), fd, pw, args);
-        dumpConfig(pw);
+
+        if (args == null || args.length == 0 || args[0].equals("--config")) {
+            dumpConfig(pw);
+        }
     }
 
     static void dumpServices(
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
index 3ff1b97..46ae84a 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
@@ -34,6 +34,7 @@
 
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.systemui.assist.AssistHandleBehaviorController.BehaviorController;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -161,6 +162,7 @@
     private final Lazy<SysUiState> mSysUiFlagContainer;
     private final Lazy<WakefulnessLifecycle> mWakefulnessLifecycle;
     private final Lazy<PackageManagerWrapper> mPackageManagerWrapper;
+    private final Lazy<BroadcastDispatcher> mBroadcastDispatcher;
 
     private boolean mOnLockscreen;
     private boolean mIsDozing;
@@ -193,7 +195,8 @@
             Lazy<OverviewProxyService> overviewProxyService,
             Lazy<SysUiState> sysUiFlagContainer,
             Lazy<WakefulnessLifecycle> wakefulnessLifecycle,
-            Lazy<PackageManagerWrapper> packageManagerWrapper) {
+            Lazy<PackageManagerWrapper> packageManagerWrapper,
+            Lazy<BroadcastDispatcher> broadcastDispatcher) {
         mClock = clock;
         mHandler = handler;
         mPhenotypeHelper = phenotypeHelper;
@@ -207,6 +210,7 @@
         for (String action : DEFAULT_HOME_CHANGE_ACTIONS) {
             mDefaultHomeIntentFilter.addAction(action);
         }
+        mBroadcastDispatcher = broadcastDispatcher;
     }
 
     @Override
@@ -215,7 +219,8 @@
         mAssistHandleCallbacks = callbacks;
         mConsecutiveTaskSwitches = 0;
         mDefaultHome = getCurrentDefaultHome();
-        context.registerReceiver(mDefaultHomeBroadcastReceiver, mDefaultHomeIntentFilter);
+        mBroadcastDispatcher.get()
+                .registerReceiver(mDefaultHomeBroadcastReceiver, mDefaultHomeIntentFilter);
         mOnLockscreen = onLockscreen(mStatusBarStateController.get().getState());
         mIsDozing = mStatusBarStateController.get().isDozing();
         mStatusBarStateController.get().addCallback(mStatusBarStateListener);
@@ -244,7 +249,7 @@
     public void onModeDeactivated() {
         mAssistHandleCallbacks = null;
         if (mContext != null) {
-            mContext.unregisterReceiver(mDefaultHomeBroadcastReceiver);
+            mBroadcastDispatcher.get().unregisterReceiver(mDefaultHomeBroadcastReceiver);
             Settings.Secure.putLong(mContext.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, 0);
             Settings.Secure.putInt(mContext.getContentResolver(), LEARNING_EVENT_COUNT_KEY, 0);
             Settings.Secure.putLong(mContext.getContentResolver(), LEARNED_HINT_LAST_SHOWN_KEY, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 1f950f6..398826c 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -44,8 +44,8 @@
 import com.android.systemui.ConfigurationChangedReceiver;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.assist.ui.DefaultUiController;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -130,6 +130,7 @@
 
     private AssistOrbContainer mView;
     private final DeviceProvisionedController mDeviceProvisionedController;
+    private final CommandQueue mCommandQueue;
     protected final AssistUtils mAssistUtils;
     private final boolean mShouldEnableOrb;
 
@@ -160,13 +161,16 @@
             DeviceProvisionedController controller,
             Context context,
             AssistUtils assistUtils,
-            AssistHandleBehaviorController handleController) {
+            AssistHandleBehaviorController handleController,
+            CommandQueue commandQueue,
+            BroadcastDispatcher broadcastDispatcher) {
         mContext = context;
         mDeviceProvisionedController = controller;
+        mCommandQueue = commandQueue;
         mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
         mAssistUtils = assistUtils;
         mAssistDisclosure = new AssistDisclosure(context, new Handler());
-        mPhoneStateMonitor = new PhoneStateMonitor(context);
+        mPhoneStateMonitor = new PhoneStateMonitor(context, broadcastDispatcher);
         mHandleController = handleController;
 
         registerVoiceInteractionSessionListener();
@@ -339,7 +343,7 @@
         }
 
         // Close Recent Apps if needed
-        SysUiServiceProvider.getComponent(mContext, CommandQueue.class).animateCollapsePanels(
+        mCommandQueue.animateCollapsePanels(
                 CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL | CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
                 false /* force */);
 
diff --git a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
index e73dc4a..95d611a 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
@@ -29,6 +29,7 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.PackageManagerWrapper;
@@ -67,7 +68,7 @@
     private boolean mLauncherShowing;
     @Nullable private ComponentName mDefaultHome;
 
-    PhoneStateMonitor(Context context) {
+    PhoneStateMonitor(Context context, BroadcastDispatcher broadcastDispatcher) {
         mContext = context;
         mStatusBarStateController = Dependency.get(StatusBarStateController.class);
 
@@ -77,7 +78,7 @@
         for (String action : DEFAULT_HOME_CHANGE_ACTIONS) {
             intentFilter.addAction(action);
         }
-        mContext.registerReceiver(new BroadcastReceiver() {
+        broadcastDispatcher.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
                 mDefaultHome = getCurrentDefaultHome();
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/EdgeLight.java b/packages/SystemUI/src/com/android/systemui/assist/ui/EdgeLight.java
index baa3a4a..c641943 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/EdgeLight.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/EdgeLight.java
@@ -67,8 +67,10 @@
     }
 
     /** Sets the edge light color. */
-    public void setColor(@ColorInt int color) {
+    public boolean setColor(@ColorInt int color) {
+        boolean changed = mColor != color;
         mColor = color;
+        return changed;
     }
 
     /** Returns the edge light length, in units of the total device perimeter. */
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
index 570b911..e5121a8 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
@@ -259,10 +259,13 @@
         if (mUseNavBarColor) {
             @ColorInt int invocationColor = (int) ArgbEvaluator.getInstance().evaluate(
                     darkIntensity, mLightColor, mDarkColor);
+            boolean changed = true;
             for (EdgeLight light : mAssistInvocationLights) {
-                light.setColor(invocationColor);
+                changed &= light.setColor(invocationColor);
             }
-            invalidate();
+            if (changed) {
+                invalidate();
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index d20cd72..f5f1fad 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -23,7 +23,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.hardware.biometrics.BiometricPrompt;
 import android.os.Bundle;
@@ -41,7 +40,6 @@
 import android.widget.TextView;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.R;
 
 import java.lang.annotation.Retention;
@@ -152,10 +150,6 @@
         public int getMediumToLargeAnimationDurationMs() {
             return AuthDialog.ANIMATE_MEDIUM_TO_LARGE_DURATION_MS;
         }
-
-        public int getAnimateCredentialStartDelayMs() {
-            return AuthDialog.ANIMATE_CREDENTIAL_START_DELAY_MS;
-        }
     }
 
     private final Injector mInjector;
@@ -632,9 +626,7 @@
      */
     void startTransitionToCredentialUI() {
         updateSize(AuthDialog.SIZE_LARGE);
-        mHandler.postDelayed(() -> {
-            mCallback.onAction(Callback.ACTION_USE_DEVICE_CREDENTIAL);
-        }, mInjector.getAnimateCredentialStartDelayMs());
+        mCallback.onAction(Callback.ACTION_USE_DEVICE_CREDENTIAL);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index f1abdb3..3948416 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -24,13 +24,12 @@
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
-import android.hardware.biometrics.Authenticator;
 import android.hardware.biometrics.BiometricAuthenticator;
-import android.hardware.biometrics.BiometricPrompt;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.IBinder;
-import android.os.UserManager;
+import android.os.Looper;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -75,6 +74,7 @@
     @interface ContainerState {}
 
     final Config mConfig;
+    private final Handler mHandler;
     private final Injector mInjector;
     private final IBinder mWindowToken = new Binder();
     private final WindowManager mWindowManager;
@@ -177,6 +177,10 @@
         View getPanelView(FrameLayout parent) {
             return parent.findViewById(R.id.panel);
         }
+
+        int getAnimateCredentialStartDelayMs() {
+            return AuthDialog.ANIMATE_CREDENTIAL_START_DELAY_MS;
+        }
     }
 
     @VisibleForTesting
@@ -201,7 +205,9 @@
                     break;
                 case AuthBiometricView.Callback.ACTION_USE_DEVICE_CREDENTIAL:
                     mConfig.mCallback.onDeviceCredentialPressed();
-                    addCredentialView(false /* animatePanel */, true /* animateContents */);
+                    mHandler.postDelayed(() -> {
+                        addCredentialView(false /* animatePanel */, true /* animateContents */);
+                    }, mInjector.getAnimateCredentialStartDelayMs());
                     break;
                 default:
                     Log.e(TAG, "Unhandled action: " + action);
@@ -223,6 +229,7 @@
         mConfig = config;
         mInjector = injector;
 
+        mHandler = new Handler(Looper.getMainLooper());
         mWindowManager = mContext.getSystemService(WindowManager.class);
         mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class);
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index b758731..516de70 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -47,16 +47,21 @@
 
 import java.util.List;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
 /**
  * Receives messages sent from {@link com.android.server.biometrics.BiometricService} and shows the
  * appropriate biometric UI (e.g. BiometricDialogView).
  */
+@Singleton
 public class AuthController extends SystemUI implements CommandQueue.Callbacks,
         AuthDialogCallback {
 
     private static final String TAG = "BiometricPrompt/AuthController";
     private static final boolean DEBUG = true;
 
+    private final CommandQueue mCommandQueue;
     private final Injector mInjector;
 
     // TODO: These should just be saved from onSaveState
@@ -93,8 +98,11 @@
                         Log.w(TAG, "Evicting client due to: " + topPackage);
                         mCurrentDialog.dismissWithoutCallback(true /* animate */);
                         mCurrentDialog = null;
-                        mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
-                        mReceiver = null;
+                        if (mReceiver != null) {
+                            mReceiver.onDialogDismissed(
+                                    BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
+                            mReceiver = null;
+                        }
                     }
                 }
             } catch (RemoteException e) {
@@ -105,6 +113,10 @@
 
     @Override
     public void onTryAgainPressed() {
+        if (mReceiver == null) {
+            Log.e(TAG, "onTryAgainPressed: Receiver is null");
+            return;
+        }
         try {
             mReceiver.onTryAgainPressed();
         } catch (RemoteException e) {
@@ -114,6 +126,10 @@
 
     @Override
     public void onDeviceCredentialPressed() {
+        if (mReceiver == null) {
+            Log.e(TAG, "onDeviceCredentialPressed: Receiver is null");
+            return;
+        }
         try {
             mReceiver.onDeviceCredentialPressed();
         } catch (RemoteException e) {
@@ -161,7 +177,7 @@
 
     private void sendResultAndCleanUp(@DismissedReason int reason) {
         if (mReceiver == null) {
-            Log.e(TAG, "Receiver is null");
+            Log.e(TAG, "sendResultAndCleanUp: Receiver is null");
             return;
         }
         try {
@@ -178,13 +194,15 @@
         }
     }
 
-    public AuthController(Context context) {
-        this(context, new Injector());
+    @Inject
+    public AuthController(Context context, CommandQueue commandQueue) {
+        this(context, commandQueue, new Injector());
     }
 
     @VisibleForTesting
-    AuthController(Context context, Injector injector) {
+    AuthController(Context context, CommandQueue commandQueue, Injector injector) {
         super(context);
+        mCommandQueue = commandQueue;
         mInjector = injector;
     }
 
@@ -194,7 +212,7 @@
         if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
                 || pm.hasSystemFeature(PackageManager.FEATURE_FACE)
                 || pm.hasSystemFeature(PackageManager.FEATURE_IRIS)) {
-            getComponent(CommandQueue.class).addCallback(this);
+            mCommandQueue.addCallback(this);
             mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
             mActivityTaskManager = mInjector.getActivityTaskManager();
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthPanelController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthPanelController.java
index 2b8b586..4acbade 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthPanelController.java
@@ -19,7 +19,6 @@
 import android.animation.AnimatorSet;
 import android.animation.ValueAnimator;
 import android.content.Context;
-import android.graphics.Color;
 import android.graphics.Outline;
 import android.util.Log;
 import android.view.View;
@@ -142,7 +141,6 @@
                 mContentHeight = (int) animation.getAnimatedValue();
                 mPanelView.invalidateOutline();
             });
-            heightAnimator.start();
 
             // Animate width
             ValueAnimator widthAnimator = ValueAnimator.ofInt(mContentWidth, contentWidth);
@@ -163,7 +161,8 @@
             AnimatorSet as = new AnimatorSet();
             as.setDuration(animateDurationMs);
             as.setInterpolator(new AccelerateDecelerateInterpolator());
-            as.playTogether(cornerAnimator, widthAnimator, marginAnimator, alphaAnimator);
+            as.playTogether(cornerAnimator, heightAnimator, widthAnimator, marginAnimator,
+                    alphaAnimator);
             as.start();
 
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
index ff4711c..776189b 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
@@ -23,6 +23,7 @@
 import android.os.Looper
 import android.os.Message
 import android.os.UserHandle
+import android.text.TextUtils
 import android.util.Log
 import android.util.SparseArray
 import com.android.internal.annotations.VisibleForTesting
@@ -55,7 +56,8 @@
  * a given broadcast.
  *
  * Use only for IntentFilters with actions and optionally categories. It does not support,
- * permissions, schemes or data types. Cannot be used for getting sticky broadcasts.
+ * permissions, schemes, data types or data authorities.
+ * Cannot be used for getting sticky broadcasts.
  */
 @Singleton
 open class BroadcastDispatcher @Inject constructor (
@@ -72,11 +74,14 @@
      *
      * @param receiver A receiver to dispatch the [Intent]
      * @param filter A filter to determine what broadcasts should be dispatched to this receiver.
-     *               It will only take into account actions and categories for filtering.
+     *               It will only take into account actions and categories for filtering. It must
+     *               have at least one action.
      * @param handler A handler to dispatch [BroadcastReceiver.onReceive]. By default, it is the
      *                main handler. Pass `null` to use the default.
      * @param user A user handle to determine which broadcast should be dispatched to this receiver.
      *             By default, it is the current user.
+     * @throws IllegalArgumentException if the filter has other constraints that are not actions or
+     *                                  categories or the filter has no actions.
      */
     @JvmOverloads
     fun registerReceiver(
@@ -85,12 +90,23 @@
         handler: Handler? = mainHandler,
         user: UserHandle = context.user
     ) {
+        checkFilter(filter)
         this.handler
                 .obtainMessage(MSG_ADD_RECEIVER,
                 ReceiverData(receiver, filter, handler ?: mainHandler, user))
                 .sendToTarget()
     }
 
+    private fun checkFilter(filter: IntentFilter) {
+        val sb = StringBuilder()
+        if (filter.countActions() == 0) sb.append("Filter must contain at least one action. ")
+        if (filter.countDataAuthorities() != 0) sb.append("Filter cannot contain DataAuthorities. ")
+        if (filter.countDataPaths() != 0) sb.append("Filter cannot contain DataPaths. ")
+        if (filter.countDataSchemes() != 0) sb.append("Filter cannot contain DataSchemes. ")
+        if (filter.countDataTypes() != 0) sb.append("Filter cannot contain DataTypes. ")
+        if (!TextUtils.isEmpty(sb)) throw IllegalArgumentException(sb.toString())
+    }
+
     /**
      * Unregister receiver for all users.
      * <br>
@@ -117,10 +133,10 @@
     protected open fun createUBRForUser(userId: Int) =
             UserBroadcastDispatcher(context, userId, mainHandler, bgLooper)
 
-    override fun dump(fd: FileDescriptor?, pw: PrintWriter?, args: Array<out String>?) {
-        pw?.println("Broadcast dispatcher:")
+    override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+        pw.println("Broadcast dispatcher:")
         for (index in 0 until receiversByUser.size()) {
-            pw?.println("  User ${receiversByUser.keyAt(index)}")
+            pw.println("  User ${receiversByUser.keyAt(index)}")
             receiversByUser.valueAt(index).dump(fd, pw, args)
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
index 54f9950..24357a7 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
@@ -31,6 +31,7 @@
 import java.io.FileDescriptor
 import java.io.PrintWriter
 import java.util.concurrent.atomic.AtomicBoolean
+import java.util.concurrent.atomic.AtomicInteger
 
 private const val MSG_REGISTER_RECEIVER = 0
 private const val MSG_UNREGISTER_RECEIVER = 1
@@ -50,6 +51,13 @@
     private val bgLooper: Looper
 ) : BroadcastReceiver(), Dumpable {
 
+    companion object {
+        // Used only for debugging. If not debugging, this variable will not be accessed and all
+        // received broadcasts will be tagged with 0. However, as DEBUG is false, nothing will be
+        // logged
+        val index = AtomicInteger(0)
+    }
+
     private val bgHandler = object : Handler(bgLooper) {
         override fun handleMessage(msg: Message) {
             when (msg.what) {
@@ -97,7 +105,10 @@
     private val receiverToReceiverData = ArrayMap<BroadcastReceiver, MutableSet<ReceiverData>>()
 
     override fun onReceive(context: Context, intent: Intent) {
-        bgHandler.post(HandleBroadcastRunnable(actionsToReceivers, context, intent, pendingResult))
+        val id = if (DEBUG) index.getAndIncrement() else 0
+        if (DEBUG) Log.w(TAG, "[$id] Received $intent")
+        bgHandler.post(
+                HandleBroadcastRunnable(actionsToReceivers, context, intent, pendingResult, id))
     }
 
     /**
@@ -149,11 +160,11 @@
         }
     }
 
-    override fun dump(fd: FileDescriptor?, pw: PrintWriter?, args: Array<out String>?) {
-        pw?.println("  Registered=${registered.get()}")
+    override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+        pw.println("  Registered=${registered.get()}")
         actionsToReceivers.forEach { (action, list) ->
-            pw?.println("    $action:")
-            list.forEach { pw?.println("      ${it.receiver}") }
+            pw.println("    $action:")
+            list.forEach { pw.println("      ${it.receiver}") }
         }
     }
 
@@ -161,17 +172,19 @@
         val actionsToReceivers: Map<String, Set<ReceiverData>>,
         val context: Context,
         val intent: Intent,
-        val pendingResult: PendingResult
+        val pendingResult: PendingResult,
+        val index: Int
     ) : Runnable {
         override fun run() {
-            if (DEBUG) Log.w(TAG, "Dispatching $intent")
+            if (DEBUG) Log.w(TAG, "[$index] Dispatching $intent")
             actionsToReceivers.get(intent.action)
                     ?.filter {
                         it.filter.hasAction(intent.action) &&
                             it.filter.matchCategories(intent.categories) == null }
                     ?.forEach {
                         it.handler.post {
-                            if (DEBUG) Log.w(TAG, "Dispatching to ${it.receiver}")
+                            if (DEBUG) Log.w(TAG,
+                                    "[$index] Dispatching ${intent.action} to ${it.receiver}")
                             it.receiver.pendingResult = pendingResult
                             it.receiver.onReceive(context, intent)
                         }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/ActivityBinder.java
deleted file mode 100644
index 4be610f..0000000
--- a/packages/SystemUI/src/com/android/systemui/dagger/ActivityBinder.java
+++ /dev/null
@@ -1,45 +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.dagger;
-
-import android.app.Activity;
-
-import com.android.systemui.ForegroundServicesDialog;
-import com.android.systemui.tuner.TunerActivity;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.IntoMap;
-
-/**
- * Services and Activities that are injectable should go here.
- */
-@Module
-public abstract class ActivityBinder {
-    /** Inject into TunerActivity. */
-    @Binds
-    @IntoMap
-    @ClassKey(TunerActivity.class)
-    public abstract Activity bindTunerActivity(TunerActivity activity);
-
-    /** Inject into ForegroundServicesDialog. */
-    @Binds
-    @IntoMap
-    @ClassKey(ForegroundServicesDialog.class)
-    public abstract Activity bindForegroundServicesDialog(ForegroundServicesDialog activity);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentHelper.java b/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentHelper.java
index d6d1e41..1e7449c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentHelper.java
@@ -18,8 +18,10 @@
 
 import android.app.Activity;
 import android.app.Service;
+import android.content.BroadcastReceiver;
 
 import com.android.systemui.SystemUI;
+import com.android.systemui.recents.RecentsImplementation;
 
 /**
  * Interface necessary to make Dagger happy. See {@link ContextComponentResolver}.
@@ -29,8 +31,14 @@
     Activity resolveActivity(String className);
 
     /** Turns a classname into an instance of the class or returns null. */
+    RecentsImplementation resolveRecents(String className);
+
+    /** Turns a classname into an instance of the class or returns null. */
     Service resolveService(String className);
 
     /** Turns a classname into an instance of the class or returns null. */
     SystemUI resolveSystemUI(String className);
+
+    /** Turns a classname into an instance of the class or returns null. */
+    BroadcastReceiver resolveBroadcastReceiver(String className);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentResolver.java b/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentResolver.java
index d7822c9..f91d795 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentResolver.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ContextComponentResolver.java
@@ -18,8 +18,10 @@
 
 import android.app.Activity;
 import android.app.Service;
+import android.content.BroadcastReceiver;
 
 import com.android.systemui.SystemUI;
+import com.android.systemui.recents.RecentsImplementation;
 
 import java.util.Map;
 
@@ -35,15 +37,20 @@
     private final Map<Class<?>, Provider<Activity>> mActivityCreators;
     private final Map<Class<?>, Provider<Service>> mServiceCreators;
     private final Map<Class<?>, Provider<SystemUI>> mSystemUICreators;
+    private final Map<Class<?>, Provider<RecentsImplementation>> mRecentsCreators;
+    private final Map<Class<?>, Provider<BroadcastReceiver>> mBroadcastReceiverCreators;
 
     @Inject
-    ContextComponentResolver(
-            Map<Class<?>, Provider<Activity>> activityCreators,
+    ContextComponentResolver(Map<Class<?>, Provider<Activity>> activityCreators,
             Map<Class<?>, Provider<Service>> serviceCreators,
-            Map<Class<?>, Provider<SystemUI>> systemUICreators) {
+            Map<Class<?>, Provider<SystemUI>> systemUICreators,
+            Map<Class<?>, Provider<RecentsImplementation>> recentsCreators,
+            Map<Class<?>, Provider<BroadcastReceiver>> broadcastReceiverCreators) {
         mActivityCreators = activityCreators;
         mServiceCreators = serviceCreators;
         mSystemUICreators = systemUICreators;
+        mRecentsCreators = recentsCreators;
+        mBroadcastReceiverCreators = broadcastReceiverCreators;
     }
 
     /**
@@ -55,6 +62,22 @@
     }
 
     /**
+     * Looks up the BroadcastReceiver class name to see if Dagger has an instance of it.
+     */
+    @Override
+    public BroadcastReceiver resolveBroadcastReceiver(String className) {
+        return resolve(className, mBroadcastReceiverCreators);
+    }
+
+    /**
+     * Looks up the RecentsImplementation class name to see if Dagger has an instance of it.
+     */
+    @Override
+    public RecentsImplementation resolveRecents(String className) {
+        return resolve(className, mRecentsCreators);
+    }
+
+    /**
      * Looks up the Service class name to see if Dagger has an instance of it.
      */
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
new file mode 100644
index 0000000..4593164
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.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.systemui.dagger;
+
+import android.app.Activity;
+
+import com.android.systemui.ForegroundServicesDialog;
+import com.android.systemui.keyguard.WorkLockActivity;
+import com.android.systemui.settings.BrightnessDialog;
+import com.android.systemui.tuner.TunerActivity;
+import com.android.systemui.usb.UsbDebuggingActivity;
+import com.android.systemui.usb.UsbDebuggingSecondaryUserActivity;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.multibindings.ClassKey;
+import dagger.multibindings.IntoMap;
+
+/**
+ * Services and Activities that are injectable should go here.
+ */
+@Module
+public abstract class DefaultActivityBinder {
+    /** Inject into TunerActivity. */
+    @Binds
+    @IntoMap
+    @ClassKey(TunerActivity.class)
+    public abstract Activity bindTunerActivity(TunerActivity activity);
+
+    /** Inject into ForegroundServicesDialog. */
+    @Binds
+    @IntoMap
+    @ClassKey(ForegroundServicesDialog.class)
+    public abstract Activity bindForegroundServicesDialog(ForegroundServicesDialog activity);
+
+    /** Inject into WorkLockActivity. */
+    @Binds
+    @IntoMap
+    @ClassKey(WorkLockActivity.class)
+    public abstract Activity bindWorkLockActivity(WorkLockActivity activity);
+
+    /** Inject into BrightnessDialog. */
+    @Binds
+    @IntoMap
+    @ClassKey(BrightnessDialog.class)
+    public abstract Activity bindBrightnessDialog(BrightnessDialog activity);
+
+    /** Inject into UsbDebuggingActivity. */
+    @Binds
+    @IntoMap
+    @ClassKey(UsbDebuggingActivity.class)
+    public abstract Activity bindUsbDebuggingActivity(UsbDebuggingActivity activity);
+
+    /** Inject into UsbDebuggingSecondaryUserActivity. */
+    @Binds
+    @IntoMap
+    @ClassKey(UsbDebuggingSecondaryUserActivity.class)
+    public abstract Activity bindUsbDebuggingSecondaryUserActivity(
+            UsbDebuggingSecondaryUserActivity activity);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ComponentBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java
similarity index 60%
copy from packages/SystemUI/src/com/android/systemui/dagger/ComponentBinder.java
copy to packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java
index 4e4c06e..56d0fa2 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ComponentBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java
@@ -16,16 +16,24 @@
 
 package com.android.systemui.dagger;
 
+import android.content.BroadcastReceiver;
+
+import com.android.systemui.screenshot.GlobalScreenshot.ActionProxyReceiver;
+
 import dagger.Binds;
 import dagger.Module;
+import dagger.multibindings.ClassKey;
+import dagger.multibindings.IntoMap;
 
 /**
- * Dagger Module that collects related sub-modules together.
+ * BroadcastReceivers that are injectable should go here.
  */
-@Module(includes = {ActivityBinder.class, ServiceBinder.class, SystemUIBinder.class})
-public abstract class ComponentBinder {
+@Module
+public abstract class DefaultBroadcastReceiverBinder {
     /** */
     @Binds
-    public abstract ContextComponentHelper bindComponentHelper(
-            ContextComponentResolver componentHelper);
+    @IntoMap
+    @ClassKey(ActionProxyReceiver.class)
+    public abstract BroadcastReceiver bindActionProxyReceiver(
+            ActionProxyReceiver broadcastReceiver);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ComponentBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultComponentBinder.java
similarity index 72%
rename from packages/SystemUI/src/com/android/systemui/dagger/ComponentBinder.java
rename to packages/SystemUI/src/com/android/systemui/dagger/DefaultComponentBinder.java
index 4e4c06e..18fe3ec 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ComponentBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultComponentBinder.java
@@ -16,16 +16,16 @@
 
 package com.android.systemui.dagger;
 
-import dagger.Binds;
 import dagger.Module;
 
 /**
  * Dagger Module that collects related sub-modules together.
+ *
+ * See {@link ContextComponentResolver}
  */
-@Module(includes = {ActivityBinder.class, ServiceBinder.class, SystemUIBinder.class})
-public abstract class ComponentBinder {
-    /** */
-    @Binds
-    public abstract ContextComponentHelper bindComponentHelper(
-            ContextComponentResolver componentHelper);
+@Module(includes = {DefaultActivityBinder.class,
+                    DefaultBroadcastReceiverBinder.class,
+                    DefaultServiceBinder.class,
+                    SystemUIBinder.class})
+public abstract class DefaultComponentBinder {
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ServiceBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
similarity index 84%
rename from packages/SystemUI/src/com/android/systemui/dagger/ServiceBinder.java
rename to packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
index 1f2c0a1..85cd51c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ServiceBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultServiceBinder.java
@@ -21,6 +21,7 @@
 import com.android.systemui.ImageWallpaper;
 import com.android.systemui.doze.DozeService;
 import com.android.systemui.keyguard.KeyguardService;
+import com.android.systemui.screenshot.TakeScreenshotService;
 
 import dagger.Binds;
 import dagger.Module;
@@ -31,7 +32,7 @@
  * Services that are injectable should go here.
  */
 @Module
-public abstract class ServiceBinder {
+public abstract class DefaultServiceBinder {
     /** */
     @Binds
     @IntoMap
@@ -49,4 +50,10 @@
     @IntoMap
     @ClassKey(KeyguardService.class)
     public abstract Service bindKeyguardService(KeyguardService service);
+
+    /** */
+    @Binds
+    @IntoMap
+    @ClassKey(TakeScreenshotService.class)
+    public abstract Service bindTakeScreenshotService(TakeScreenshotService service);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
index 6674c12..9032c6f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
@@ -20,6 +20,7 @@
 import com.android.systemui.appops.AppOpsController;
 import com.android.systemui.appops.AppOpsControllerImpl;
 import com.android.systemui.classifier.FalsingManagerProxy;
+import com.android.systemui.doze.DozeHost;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.FalsingManager;
@@ -33,6 +34,7 @@
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
+import com.android.systemui.statusbar.phone.DozeServiceHost;
 import com.android.systemui.statusbar.phone.ManagedProfileController;
 import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -241,5 +243,10 @@
     /**
      */
     @Binds
-    public abstract FalsingManager provideFalsingmanager(FalsingManagerProxy falsingManagerImpl);
+    public abstract FalsingManager provideFalsingManager(FalsingManagerProxy falsingManagerImpl);
+
+    /**
+     */
+    @Binds
+    public abstract DozeHost provideDozeHost(DozeServiceHost dozeServiceHost);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 87434f3..6d61b2f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -27,12 +27,15 @@
 import android.os.Looper;
 import android.os.Process;
 import android.os.ServiceManager;
+import android.os.UserManager;
 import android.util.DisplayMetrics;
 import android.view.IWindowManager;
+import android.view.LayoutInflater;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.BgHandler;
 import com.android.systemui.dagger.qualifiers.BgLooper;
 import com.android.systemui.dagger.qualifiers.MainHandler;
@@ -43,6 +46,7 @@
 import com.android.systemui.shared.plugins.PluginManagerImpl;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NavigationBarController;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.phone.AutoHideController;
@@ -152,6 +156,13 @@
                 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
     }
 
+    /** */
+    @Singleton
+    @Provides
+    public LayoutInflater providerLayoutInflater(Context context) {
+        return LayoutInflater.from(context);
+    }
+
     @Singleton
     @Provides
     public LeakDetector provideLeakDetector() {
@@ -181,8 +192,8 @@
     @Singleton
     @Provides
     public NavigationBarController provideNavigationBarController(Context context,
-            @MainHandler Handler mainHandler) {
-        return new NavigationBarController(context, mainHandler);
+            @MainHandler Handler mainHandler, CommandQueue commandQueue) {
+        return new NavigationBarController(context, mainHandler, commandQueue);
     }
 
     @Singleton
@@ -216,8 +227,8 @@
     @Singleton
     @Provides
     public DeviceProvisionedController provideDeviceProvisionedController(Context context,
-            @MainHandler Handler mainHandler) {
-        return new DeviceProvisionedControllerImpl(context, mainHandler);
+            @MainHandler Handler mainHandler, BroadcastDispatcher broadcastDispatcher) {
+        return new DeviceProvisionedControllerImpl(context, mainHandler, broadcastDispatcher);
     }
 
     /** */
@@ -231,4 +242,11 @@
     public AlwaysOnDisplayPolicy provideAlwaysOnDisplayPolicy(Context context) {
         return new AlwaysOnDisplayPolicy(context);
     }
+
+    /** */
+    @Singleton
+    @Provides
+    public UserManager providesUserManager(Context context) {
+        return context.getSystemService(UserManager.class);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
index 434e2d3..fffba8c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java
@@ -34,6 +34,7 @@
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 
+import com.android.internal.util.LatencyTracker;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.systemui.dagger.qualifiers.BgHandler;
 import com.android.systemui.dagger.qualifiers.MainResources;
@@ -58,12 +59,13 @@
 
     @Singleton
     @Provides
-    static IActivityManager providesIActivityManager() {
+    static IActivityManager provideIActivityManager() {
         return ActivityManager.getService();
     }
 
     @Provides
-    static IWallpaperManager provideWallPaperManager() {
+    @Nullable
+    static IWallpaperManager provideIWallPaperManager() {
         return IWallpaperManager.Stub.asInterface(
                 ServiceManager.getService(Context.WALLPAPER_SERVICE));
     }
@@ -74,6 +76,12 @@
         return WindowManagerGlobal.getWindowManagerService();
     }
 
+    @Singleton
+    @Provides
+    static LatencyTracker provideLatencyTracker(Context context) {
+        return LatencyTracker.getInstance(context);
+    }
+
     @SuppressLint("MissingPermission")
     @Singleton
     @Provides
@@ -109,13 +117,13 @@
     }
 
     @Provides
-    static WallpaperManager providesWallpaperManager(Context context) {
+    static WallpaperManager provideWallpaperManager(Context context) {
         return (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
     }
 
     @Singleton
     @Provides
-    static WindowManager providesWindowManager(Context context) {
+    static WindowManager provideWindowManager(Context context) {
         return context.getSystemService(WindowManager.class);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 49cd414..3b0c9ae 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -16,17 +16,102 @@
 
 package com.android.systemui.dagger;
 
+import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
+
+import android.content.Context;
+import android.os.PowerManager;
+import android.util.DisplayMetrics;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.LatencyTester;
+import com.android.systemui.ScreenDecorations;
+import com.android.systemui.SizeCompatModeActivityController;
+import com.android.systemui.SliceBroadcastRelayHandler;
 import com.android.systemui.SystemUI;
+import com.android.systemui.UiOffloadThread;
+import com.android.systemui.appops.AppOpsController;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.doze.DozeLog;
+import com.android.systemui.globalactions.GlobalActionsComponent;
 import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.pip.PipUI;
+import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.power.PowerUI;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsModule;
+import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.statusbar.NavigationBarController;
+import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationViewHierarchyManager;
+import com.android.systemui.statusbar.PulseExpansionHandler;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
+import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.InstantAppNotifier;
+import com.android.systemui.statusbar.notification.NewNotifPipeline;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+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.logging.NotifLog;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.phone.AutoHideController;
+import com.android.systemui.statusbar.phone.BiometricUnlockController;
+import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.phone.DozeScrimController;
+import com.android.systemui.statusbar.phone.DozeServiceHost;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.KeyguardLiftController;
+import com.android.systemui.statusbar.phone.LightBarController;
+import com.android.systemui.statusbar.phone.LockscreenWallpaper;
+import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.StatusBarWindowController;
+import com.android.systemui.statusbar.phone.StatusBarWindowViewController;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
+import com.android.systemui.statusbar.policy.RemoteInputUriController;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.tv.TvStatusBar;
+import com.android.systemui.theme.ThemeOverlayController;
+import com.android.systemui.util.InjectionInflationController;
 import com.android.systemui.util.leak.GarbageMonitor;
 import com.android.systemui.volume.VolumeUI;
 
+import javax.inject.Named;
+import javax.inject.Singleton;
+
 import dagger.Binds;
+import dagger.Lazy;
 import dagger.Module;
+import dagger.Provides;
 import dagger.multibindings.ClassKey;
 import dagger.multibindings.IntoMap;
 
@@ -35,6 +120,11 @@
  */
 @Module(includes = {RecentsModule.class})
 public abstract class SystemUIBinder {
+    /** Inject into AuthController. */
+    @Binds
+    @IntoMap
+    @ClassKey(AuthController.class)
+    public abstract SystemUI bindAuthController(AuthController service);
 
     /** Inject into GarbageMonitor.Service. */
     @Binds
@@ -42,12 +132,30 @@
     @ClassKey(GarbageMonitor.Service.class)
     public abstract SystemUI bindGarbageMonitorService(GarbageMonitor.Service service);
 
+    /** Inject into GlobalActionsComponent. */
+    @Binds
+    @IntoMap
+    @ClassKey(GlobalActionsComponent.class)
+    public abstract SystemUI bindGlobalActionsComponent(GlobalActionsComponent sysui);
+
+    /** Inject into InstantAppNotifier. */
+    @Binds
+    @IntoMap
+    @ClassKey(InstantAppNotifier.class)
+    public abstract SystemUI bindInstantAppNotifier(InstantAppNotifier sysui);
+
     /** Inject into KeyguardViewMediator. */
     @Binds
     @IntoMap
     @ClassKey(KeyguardViewMediator.class)
     public abstract SystemUI bindKeyguardViewMediator(KeyguardViewMediator sysui);
 
+    /** Inject into LatencyTests. */
+    @Binds
+    @IntoMap
+    @ClassKey(LatencyTester.class)
+    public abstract SystemUI bindLatencyTester(LatencyTester sysui);
+
     /** Inject into PipUI. */
     @Binds
     @IntoMap
@@ -66,10 +174,190 @@
     @ClassKey(Recents.class)
     public abstract SystemUI bindRecents(Recents sysui);
 
+    /** Inject into ScreenDecorations. */
+    @Binds
+    @IntoMap
+    @ClassKey(ScreenDecorations.class)
+    public abstract SystemUI bindScreenDecorations(ScreenDecorations sysui);
+
+    /** Inject into SizeCompatModeActivityController. */
+    @Binds
+    @IntoMap
+    @ClassKey(SizeCompatModeActivityController.class)
+    public abstract SystemUI bindsSizeCompatModeActivityController(
+            SizeCompatModeActivityController sysui);
+
+    /** Inject into SliceBroadcastRelayHandler. */
+    @Binds
+    @IntoMap
+    @ClassKey(SliceBroadcastRelayHandler.class)
+    public abstract SystemUI bindSliceBroadcastRelayHandler(SliceBroadcastRelayHandler sysui);
+
+    /** Inject into StatusBar. */
+    @Binds
+    @IntoMap
+    @ClassKey(StatusBar.class)
+    public abstract SystemUI bindsStatusBar(StatusBar sysui);
+
+    /** Inject into ThemeOverlayController. */
+    @Binds
+    @IntoMap
+    @ClassKey(ThemeOverlayController.class)
+    public abstract SystemUI bindThemeOverlayController(ThemeOverlayController sysui);
+
+    /** Inject into TvStatusBar. */
+    @Binds
+    @IntoMap
+    @ClassKey(TvStatusBar.class)
+    public abstract SystemUI bindsTvStatusBar(TvStatusBar sysui);
+
     /** Inject into VolumeUI. */
     @Binds
     @IntoMap
     @ClassKey(VolumeUI.class)
     public abstract SystemUI bindVolumeUI(VolumeUI sysui);
 
+    /**
+     * Provides our instance of StatusBar which is considered optional.
+     */
+    @Provides
+    @Singleton
+    static StatusBar provideStatusBar(
+            Context context,
+            FeatureFlags featureFlags,
+            LightBarController lightBarController,
+            AutoHideController autoHideController,
+            KeyguardUpdateMonitor keyguardUpdateMonitor,
+            StatusBarIconController statusBarIconController,
+            DozeLog dozeLog,
+            InjectionInflationController injectionInflationController,
+            PulseExpansionHandler pulseExpansionHandler,
+            NotificationWakeUpCoordinator notificationWakeUpCoordinator,
+            KeyguardBypassController keyguardBypassController,
+            KeyguardStateController keyguardStateController,
+            HeadsUpManagerPhone headsUpManagerPhone,
+            DynamicPrivacyController dynamicPrivacyController,
+            BypassHeadsUpNotifier bypassHeadsUpNotifier,
+            @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowNotificationLongPress,
+            Lazy<NewNotifPipeline> newNotifPipeline,
+            FalsingManager falsingManager,
+            BroadcastDispatcher broadcastDispatcher,
+            RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
+            NotificationGutsManager notificationGutsManager,
+            NotificationLogger notificationLogger,
+            NotificationEntryManager notificationEntryManager,
+            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+            NotificationViewHierarchyManager notificationViewHierarchyManager,
+            ForegroundServiceController foregroundServiceController,
+            AppOpsController appOpsController,
+            KeyguardViewMediator keyguardViewMediator,
+            ZenModeController zenModeController,
+            NotificationAlertingManager notificationAlertingManager,
+            DisplayMetrics displayMetrics,
+            MetricsLogger metricsLogger,
+            UiOffloadThread uiOffloadThread,
+            NotificationMediaManager notificationMediaManager,
+            NotificationLockscreenUserManager lockScreenUserManager,
+            NotificationRemoteInputManager remoteInputManager,
+            UserSwitcherController userSwitcherController,
+            NetworkController networkController,
+            BatteryController batteryController,
+            SysuiColorExtractor colorExtractor,
+            ScreenLifecycle screenLifecycle,
+            WakefulnessLifecycle wakefulnessLifecycle,
+            SysuiStatusBarStateController statusBarStateController,
+            VibratorHelper vibratorHelper,
+            BubbleController bubbleController,
+            NotificationGroupManager groupManager,
+            NotificationGroupAlertTransferHelper groupAlertTransferHelper,
+            VisualStabilityManager visualStabilityManager,
+            DeviceProvisionedController deviceProvisionedController,
+            NavigationBarController navigationBarController,
+            AssistManager assistManager,
+            NotificationListener notificationListener,
+            ConfigurationController configurationController,
+            StatusBarWindowController statusBarWindowController,
+            StatusBarWindowViewController.Builder statusBarWindowViewControllerBuilder,
+            NotifLog notifLog,
+            DozeParameters dozeParameters,
+            ScrimController scrimController,
+            @Nullable KeyguardLiftController keyguardLiftController,
+            Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
+            Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
+            DozeServiceHost dozeServiceHost,
+            PowerManager powerManager,
+            DozeScrimController dozeScrimController,
+            CommandQueue commandQueue,
+            PluginManager pluginManager,
+            RemoteInputUriController remoteInputUriController) {
+        return new StatusBar(
+                context,
+                featureFlags,
+                lightBarController,
+                autoHideController,
+                keyguardUpdateMonitor,
+                statusBarIconController,
+                dozeLog,
+                injectionInflationController,
+                pulseExpansionHandler,
+                notificationWakeUpCoordinator,
+                keyguardBypassController,
+                keyguardStateController,
+                headsUpManagerPhone,
+                dynamicPrivacyController,
+                bypassHeadsUpNotifier,
+                allowNotificationLongPress,
+                newNotifPipeline,
+                falsingManager,
+                broadcastDispatcher,
+                remoteInputQuickSettingsDisabler,
+                notificationGutsManager,
+                notificationLogger,
+                notificationEntryManager,
+                notificationInterruptionStateProvider,
+                notificationViewHierarchyManager,
+                foregroundServiceController,
+                appOpsController,
+                keyguardViewMediator,
+                zenModeController,
+                notificationAlertingManager,
+                displayMetrics,
+                metricsLogger,
+                uiOffloadThread,
+                notificationMediaManager,
+                lockScreenUserManager,
+                remoteInputManager,
+                userSwitcherController,
+                networkController,
+                batteryController,
+                colorExtractor,
+                screenLifecycle,
+                wakefulnessLifecycle,
+                statusBarStateController,
+                vibratorHelper,
+                bubbleController,
+                groupManager,
+                groupAlertTransferHelper,
+                visualStabilityManager,
+                deviceProvisionedController,
+                navigationBarController,
+                assistManager,
+                notificationListener,
+                configurationController,
+                statusBarWindowController,
+                statusBarWindowViewControllerBuilder,
+                notifLog,
+                dozeParameters,
+                scrimController,
+                keyguardLiftController,
+                lockscreenWallpaperLazy,
+                biometricUnlockControllerLazy,
+                dozeServiceHost,
+                powerManager,
+                dozeScrimController,
+                commandQueue,
+                pluginManager,
+                remoteInputUriController);
+    }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index c95b50b..7b8d3bc 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -21,7 +21,6 @@
 
 import androidx.annotation.Nullable;
 
-import com.android.systemui.SystemUI;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dock.DockManagerImpl;
 import com.android.systemui.power.EnhancedEstimates;
@@ -39,8 +38,6 @@
 import dagger.Binds;
 import dagger.Module;
 import dagger.Provides;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.IntoMap;
 
 /**
  * A dagger module for injecting default implementations of components of System UI that may be
@@ -74,11 +71,6 @@
     @Binds
     abstract ShadeController provideShadeController(StatusBar statusBar);
 
-    @Binds
-    @IntoMap
-    @ClassKey(StatusBar.class)
-    public abstract SystemUI providesStatusBar(StatusBar statusBar);
-
     @Singleton
     @Provides
     @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME)
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 30f1397..9e7f6c6 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -20,15 +20,20 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.DumpController;
 import com.android.systemui.assist.AssistModule;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.people.PeopleHubModule;
 import com.android.systemui.statusbar.phone.KeyguardLiftController;
+import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.util.sensors.AsyncSensorManager;
 
 import javax.inject.Singleton;
 
+import dagger.Binds;
+import dagger.BindsOptionalOf;
 import dagger.Module;
 import dagger.Provides;
 
@@ -36,25 +41,35 @@
  * A dagger module for injecting components of System UI that are not overridden by the System UI
  * implementation.
  */
-@Module(includes = {AssistModule.class, ComponentBinder.class, PeopleHubModule.class})
+@Module(includes = {AssistModule.class,
+                    PeopleHubModule.class})
 public abstract class SystemUIModule {
+    /** */
+    @Binds
+    public abstract ContextComponentHelper bindComponentHelper(
+            ContextComponentResolver componentHelper);
 
     @Singleton
     @Provides
     @Nullable
     static KeyguardLiftController provideKeyguardLiftController(Context context,
             StatusBarStateController statusBarStateController,
-            AsyncSensorManager asyncSensorManager) {
+            AsyncSensorManager asyncSensorManager,
+            KeyguardUpdateMonitor keyguardUpdateMonitor,
+            DumpController dumpController) {
         if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
             return null;
         }
-        return new KeyguardLiftController(statusBarStateController, asyncSensorManager);
+        return new KeyguardLiftController(statusBarStateController, asyncSensorManager,
+                keyguardUpdateMonitor, dumpController);
     }
 
-
     @Singleton
     @Provides
     static SysUiState provideSysUiState() {
         return new SysUiState();
     }
+
+    @BindsOptionalOf
+    abstract StatusBar optionalStatusBar();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
index 113c9c8..83d956c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
@@ -37,6 +37,7 @@
  */
 @Singleton
 @Component(modules = {
+        DefaultComponentBinder.class,
         DependencyProvider.class,
         DependencyBinder.class,
         SystemServicesModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index a36ff0d..eaa72dc 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -29,6 +29,7 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.R;
 import com.android.systemui.SystemUIApplication;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.plugins.FalsingManager;
@@ -57,6 +58,8 @@
     private final ProximitySensor mProximitySensor;
     private final DelayedWakeLock.Builder mDelayedWakeLockBuilder;
     private final Handler mHandler;
+    private final BiometricUnlockController mBiometricUnlockController;
+    private final BroadcastDispatcher mBroadcastDispatcher;
 
     @Inject
     public DozeFactory(FalsingManager falsingManager, DozeLog dozeLog,
@@ -65,7 +68,9 @@
             WakefulnessLifecycle wakefulnessLifecycle, KeyguardUpdateMonitor keyguardUpdateMonitor,
             DockManager dockManager, @Nullable IWallpaperManager wallpaperManager,
             ProximitySensor proximitySensor,
-            DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler) {
+            DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
+            BiometricUnlockController biometricUnlockController,
+            BroadcastDispatcher broadcastDispatcher) {
         mFalsingManager = falsingManager;
         mDozeLog = dozeLog;
         mDozeParameters = dozeParameters;
@@ -79,6 +84,8 @@
         mProximitySensor = proximitySensor;
         mDelayedWakeLockBuilder = delayedWakeLockBuilder;
         mHandler = handler;
+        mBiometricUnlockController = biometricUnlockController;
+        mBroadcastDispatcher = broadcastDispatcher;
     }
 
     /** Creates a DozeMachine with its parts for {@code dozeService}. */
@@ -107,9 +114,7 @@
                 createDozeScreenBrightness(dozeService, wrappedService, mAsyncSensorManager, host,
                         mDozeParameters, mHandler),
                 new DozeWallpaperState(
-                        mWallpaperManager,
-                        getBiometricUnlockController(dozeService),
-                        mDozeParameters),
+                        mWallpaperManager, mBiometricUnlockController, mDozeParameters),
                 new DozeDockHandler(dozeService, machine, host, config, mHandler, mDockManager),
                 new DozeAuthRemover(dozeService)
         });
@@ -122,8 +127,8 @@
             DozeParameters params, Handler handler) {
         Sensor sensor = DozeSensors.findSensorWithType(sensorManager,
                 context.getString(R.string.doze_brightness_sensor_type));
-        return new DozeScreenBrightness(context, service, sensorManager, sensor, host, handler,
-                params.getPolicy());
+        return new DozeScreenBrightness(context, service, sensorManager, sensor,
+                mBroadcastDispatcher, host, handler, params.getPolicy());
     }
 
     private DozeTriggers createDozeTriggers(Context context, AsyncSensorManager sensorManager,
@@ -133,7 +138,7 @@
         boolean allowPulseTriggers = true;
         return new DozeTriggers(context, machine, host, alarmManager, config, params,
                 sensorManager, handler, wakeLock, allowPulseTriggers, dockManager,
-                mProximitySensor, dozeLog);
+                mProximitySensor, dozeLog, mBroadcastDispatcher);
 
     }
 
@@ -149,10 +154,4 @@
         final SystemUIApplication app = (SystemUIApplication) appCandidate;
         return app.getComponent(DozeHost.class);
     }
-
-    public static BiometricUnlockController getBiometricUnlockController(DozeService service) {
-        Application appCandidate = service.getApplication();
-        final SystemUIApplication app = (SystemUIApplication) appCandidate;
-        return app.getComponent(BiometricUnlockController.class);
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 1a6bd60..d1047e2 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -68,6 +68,12 @@
      */
     void prepareForGentleSleep(Runnable onDisplayOffCallback);
 
+    /**
+     * Cancel pending {@code onDisplayOffCallback} callback.
+     * @see #prepareForGentleSleep(Runnable)
+     */
+    void cancelGentleSleep();
+
     void onIgnoreTouchWhilePulsing(boolean ignore);
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index bd6882c..39a2562 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -31,6 +31,7 @@
 import android.provider.Settings;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 
 /**
  * Controls the screen brightness when dozing.
@@ -49,6 +50,7 @@
     private final Handler mHandler;
     private final SensorManager mSensorManager;
     private final Sensor mLightSensor;
+    private final BroadcastDispatcher mBroadcastDispatcher;
     private final int[] mSensorToBrightness;
     private final int[] mSensorToScrimOpacity;
     private final boolean mDebuggable;
@@ -69,13 +71,15 @@
 
     @VisibleForTesting
     public DozeScreenBrightness(Context context, DozeMachine.Service service,
-            SensorManager sensorManager, Sensor lightSensor, DozeHost host,
+            SensorManager sensorManager, Sensor lightSensor,
+            BroadcastDispatcher broadcastDispatcher, DozeHost host,
             Handler handler, int defaultDozeBrightness, int[] sensorToBrightness,
             int[] sensorToScrimOpacity, boolean debuggable) {
         mContext = context;
         mDozeService = service;
         mSensorManager = sensorManager;
         mLightSensor = lightSensor;
+        mBroadcastDispatcher = broadcastDispatcher;
         mDozeHost = host;
         mHandler = handler;
         mDebuggable = debuggable;
@@ -87,14 +91,15 @@
         if (mDebuggable) {
             IntentFilter filter = new IntentFilter();
             filter.addAction(ACTION_AOD_BRIGHTNESS);
-            mContext.registerReceiverAsUser(this, UserHandle.ALL, filter, null, handler);
+            mBroadcastDispatcher.registerReceiver(this, filter, handler, UserHandle.ALL);
         }
     }
 
     public DozeScreenBrightness(Context context, DozeMachine.Service service,
-            SensorManager sensorManager, Sensor lightSensor, DozeHost host,
-            Handler handler, AlwaysOnDisplayPolicy policy) {
-        this(context, service, sensorManager, lightSensor, host, handler,
+            SensorManager sensorManager, Sensor lightSensor,
+            BroadcastDispatcher broadcastDispatcher, DozeHost host, Handler handler,
+            AlwaysOnDisplayPolicy policy) {
+        this(context, service, sensorManager, lightSensor, broadcastDispatcher, host, handler,
                 context.getResources().getInteger(
                         com.android.internal.R.integer.config_screenBrightnessDoze),
                 policy.screenBrightnessArray, policy.dimmingScrimArray, DEBUG_AOD_BRIGHTNESS);
@@ -127,7 +132,7 @@
     private void onDestroy() {
         setLightSensorEnabled(false);
         if (mDebuggable) {
-            mContext.unregisterReceiver(this);
+            mBroadcastDispatcher.unregisterReceiver(this);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index 95c42fc..e1b4f31 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -71,7 +71,7 @@
     @Override
     public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
         int screenState = newState.screenState(mParameters);
-        mDozeHost.prepareForGentleSleep(null);
+        mDozeHost.cancelGentleSleep();
 
         if (newState == DozeMachine.State.FINISH) {
             // Make sure not to apply the screen state after DozeService was destroyed.
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index b212884..1134268 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -36,6 +36,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Dependency;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.Assert;
@@ -80,6 +81,7 @@
     private final DockEventListener mDockEventListener = new DockEventListener();
     private final DockManager mDockManager;
     private final ProximitySensor.ProximityCheck mProxCheck;
+    private final BroadcastDispatcher mBroadcastDispatcher;
 
     private long mNotificationPulseTime;
     private boolean mPulsePending;
@@ -91,7 +93,7 @@
             DozeParameters dozeParameters, AsyncSensorManager sensorManager, Handler handler,
             WakeLock wakeLock, boolean allowPulseTriggers, DockManager dockManager,
             ProximitySensor proximitySensor,
-            DozeLog dozeLog) {
+            DozeLog dozeLog, BroadcastDispatcher broadcastDispatcher) {
         mContext = context;
         mMachine = machine;
         mDozeHost = dozeHost;
@@ -107,6 +109,7 @@
         mDockManager = dockManager;
         mProxCheck = new ProximitySensor.ProximityCheck(proximitySensor, handler);
         mDozeLog = dozeLog;
+        mBroadcastDispatcher = broadcastDispatcher;
     }
 
     private void onNotification(Runnable onPulseSuppressedListener) {
@@ -299,7 +302,7 @@
     public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
         switch (newState) {
             case INITIALIZED:
-                mBroadcastReceiver.register(mContext);
+                mBroadcastReceiver.register(mBroadcastDispatcher);
                 mDozeHost.addCallback(mHostCallback);
                 if (mDockManager != null) {
                     mDockManager.addListener(mDockEventListener);
@@ -334,7 +337,7 @@
                 mDozeSensors.updateListening();
                 break;
             case FINISH:
-                mBroadcastReceiver.unregister(mContext);
+                mBroadcastReceiver.unregister(mBroadcastDispatcher);
                 mDozeHost.removeCallback(mHostCallback);
                 if (mDockManager != null) {
                     mDockManager.removeListener(mDockEventListener);
@@ -437,22 +440,22 @@
             }
         }
 
-        public void register(Context context) {
+        public void register(BroadcastDispatcher broadcastDispatcher) {
             if (mRegistered) {
                 return;
             }
             IntentFilter filter = new IntentFilter(PULSE_ACTION);
             filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE);
             filter.addAction(Intent.ACTION_USER_SWITCHED);
-            context.registerReceiver(this, filter);
+            broadcastDispatcher.registerReceiver(this, filter);
             mRegistered = true;
         }
 
-        public void unregister(Context context) {
+        public void unregister(BroadcastDispatcher broadcastDispatcher) {
             if (!mRegistered) {
                 return;
             }
-            context.unregisterReceiver(this);
+            broadcastDispatcher.unregisterReceiver(this);
             mRegistered = false;
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
index c11127d..19b6f82 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
@@ -20,7 +20,6 @@
 
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.Dependency;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.SystemUI;
 import com.android.systemui.plugins.GlobalActions;
 import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
@@ -29,14 +28,24 @@
 import com.android.systemui.statusbar.policy.ExtensionController;
 import com.android.systemui.statusbar.policy.ExtensionController.Extension;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Manages power menu plugins and communicates power menu actions to the StatusBar.
+ */
+@Singleton
 public class GlobalActionsComponent extends SystemUI implements Callbacks, GlobalActionsManager {
 
+    private final CommandQueue mCommandQueue;
     private GlobalActions mPlugin;
     private Extension<GlobalActions> mExtension;
     private IStatusBarService mBarService;
 
-    public GlobalActionsComponent(Context context) {
+    @Inject
+    public GlobalActionsComponent(Context context, CommandQueue commandQueue) {
         super(context);
+        mCommandQueue = commandQueue;
     }
 
     @Override
@@ -45,11 +54,11 @@
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
         mExtension = Dependency.get(ExtensionController.class).newExtension(GlobalActions.class)
                 .withPlugin(GlobalActions.class)
-                .withDefault(() -> new GlobalActionsImpl(mContext))
+                .withDefault(() -> new GlobalActionsImpl(mContext, mCommandQueue))
                 .withCallback(this::onExtensionCallback)
                 .build();
         mPlugin = mExtension.get();
-        SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallback(this);
+        mCommandQueue.addCallback(this);
     }
 
     private void onExtensionCallback(GlobalActions newPlugin) {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 22846bc..bb2d142 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -52,6 +52,7 @@
 import android.provider.Settings;
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
+import android.telecom.TelecomManager;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
@@ -145,6 +146,7 @@
     private final DevicePolicyManager mDevicePolicyManager;
     private final LockPatternUtils mLockPatternUtils;
     private final KeyguardManager mKeyguardManager;
+    private final BroadcastDispatcher mBroadcastDispatcher;
 
     private ArrayList<Action> mItems;
     private ActionsDialog mDialog;
@@ -182,13 +184,14 @@
                 Context.DEVICE_POLICY_SERVICE);
         mLockPatternUtils = new LockPatternUtils(mContext);
         mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+        mBroadcastDispatcher = Dependency.get(BroadcastDispatcher.class);
 
         // receive broadcasts
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
-        Dependency.get(BroadcastDispatcher.class).registerReceiver(mBroadcastReceiver, filter);
+        mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter);
 
         ConnectivityManager cm = (ConnectivityManager)
                 context.getSystemService(Context.CONNECTIVITY_SERVICE);
@@ -563,7 +566,8 @@
         @Override
         public void onPress() {
             MetricsLogger.action(mContext, MetricsEvent.ACTION_EMERGENCY_DIALER_FROM_POWER_MENU);
-            Intent intent = new Intent(EmergencyDialerConstants.ACTION_DIAL);
+            Intent intent = mContext.getSystemService(TelecomManager.class)
+                    .createLaunchEmergencyDialerIntent(null /* number */);
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                     | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
                     | Intent.FLAG_ACTIVITY_CLEAR_TOP);
@@ -899,7 +903,7 @@
         mAdapter.notifyDataSetChanged();
         if (mShowSilentToggle) {
             IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
-            mContext.registerReceiver(mRingerModeReceiver, filter);
+            mBroadcastDispatcher.registerReceiver(mRingerModeReceiver, filter);
         }
     }
 
@@ -917,7 +921,7 @@
         mWindowManagerFuncs.onGlobalActionsHidden();
         if (mShowSilentToggle) {
             try {
-                mContext.unregisterReceiver(mRingerModeReceiver);
+                mBroadcastDispatcher.unregisterReceiver(mRingerModeReceiver);
             } catch (IllegalArgumentException ie) {
                 // ignore this
                 Log.w(TAG, ie);
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index b9fe827..d5f5a5a 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -33,16 +33,18 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.plugins.GlobalActions;
 import com.android.systemui.plugins.GlobalActionsPanelPlugin;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.ExtensionController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
-public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks {
+public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks,
+        PluginListener<GlobalActionsPanelPlugin> {
 
     private static final float SHUTDOWN_SCRIM_ALPHA = 0.95f;
 
@@ -50,23 +52,35 @@
     private final KeyguardStateController mKeyguardStateController;
     private final DeviceProvisionedController mDeviceProvisionedController;
     private final ExtensionController.Extension<GlobalActionsPanelPlugin> mPanelExtension;
+    private GlobalActionsPanelPlugin mPlugin;
+    private final CommandQueue mCommandQueue;
     private GlobalActionsDialog mGlobalActions;
     private boolean mDisabled;
+    private final PluginManager mPluginManager;
+    private final String mPluginPackageName;
 
-    public GlobalActionsImpl(Context context) {
+    public GlobalActionsImpl(Context context, CommandQueue commandQueue) {
         mContext = context;
         mKeyguardStateController = Dependency.get(KeyguardStateController.class);
         mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
-        SysUiServiceProvider.getComponent(context, CommandQueue.class).addCallback(this);
+        mPluginManager = Dependency.get(PluginManager.class);
+        mCommandQueue = commandQueue;
+        mCommandQueue.addCallback(this);
         mPanelExtension = Dependency.get(ExtensionController.class)
                 .newExtension(GlobalActionsPanelPlugin.class)
                 .withPlugin(GlobalActionsPanelPlugin.class)
                 .build();
+        mPluginPackageName = mContext.getString(
+                com.android.systemui.R.string.config_controlsPluginPackageName);
+        mPluginManager.addPluginListener(
+                GlobalActionsPanelPlugin.ACTION, this, GlobalActionsPanelPlugin.class, true);
     }
 
     @Override
     public void destroy() {
-        SysUiServiceProvider.getComponent(mContext, CommandQueue.class).removeCallback(this);
+        mCommandQueue.removeCallback(this);
+        mPluginManager.removePluginListener(this);
+        if (mPlugin != null) mPlugin.onDestroy();
         if (mGlobalActions != null) {
             mGlobalActions.destroy();
             mGlobalActions = null;
@@ -81,7 +95,7 @@
         }
         mGlobalActions.showDialog(mKeyguardStateController.isShowing(),
                 mDeviceProvisionedController.isDeviceProvisioned(),
-                mPanelExtension.get());
+                mPlugin != null ? mPlugin : mPanelExtension.get());
         Dependency.get(KeyguardUpdateMonitor.class).requestFaceAuth();
     }
 
@@ -144,4 +158,16 @@
             mGlobalActions.dismissDialog();
         }
     }
+
+    @Override
+    public void onPluginConnected(GlobalActionsPanelPlugin plugin, Context pluginContext) {
+        if (pluginContext.getPackageName().equals(mPluginPackageName)) {
+            mPlugin = plugin;
+        }
+    }
+
+    @Override
+    public void onPluginDisconnected(GlobalActionsPanelPlugin plugin) {
+        mPlugin = null;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 411bf9a..3b1edcc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -87,6 +87,7 @@
 import com.android.systemui.SystemUI;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.UiOffloadThread;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.statusbar.phone.BiometricUnlockController;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -319,6 +320,7 @@
      */
     private boolean mWaitingUntilKeyguardVisible = false;
     private final LockPatternUtils mLockPatternUtils;
+    private final BroadcastDispatcher mBroadcastDispatcher;
     private boolean mKeyguardDonePending = false;
     private boolean mHideAnimationRun = false;
     private boolean mHideAnimationRunning = false;
@@ -685,8 +687,10 @@
     public KeyguardViewMediator(
             Context context,
             FalsingManager falsingManager,
-            LockPatternUtils lockPatternUtils) {
-        this(context, falsingManager, lockPatternUtils, SystemUIFactory.getInstance());
+            LockPatternUtils lockPatternUtils,
+            BroadcastDispatcher broadcastDispatcher) {
+        this(context, falsingManager, lockPatternUtils, broadcastDispatcher,
+                SystemUIFactory.getInstance());
     }
 
     @VisibleForTesting
@@ -694,10 +698,12 @@
             Context context,
             FalsingManager falsingManager,
             LockPatternUtils lockPatternUtils,
+            BroadcastDispatcher broadcastDispatcher,
             SystemUIFactory systemUIFactory) {
         super(context);
         mFalsingManager = falsingManager;
         mLockPatternUtils = lockPatternUtils;
+        mBroadcastDispatcher = broadcastDispatcher;
         mStatusBarKeyguardViewManager = systemUIFactory.createStatusBarKeyguardViewManager(
                 mContext,
                 mViewMediatorCallback,
@@ -722,7 +728,7 @@
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_SHUTDOWN);
-        mContext.registerReceiver(mBroadcastReceiver, filter);
+        mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter);
 
         final IntentFilter delayedActionFilter = new IntentFilter();
         delayedActionFilter.addAction(DELAYED_KEYGUARD_ACTION);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
index 4d061e1..b1df578 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
@@ -36,6 +36,9 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+
+import javax.inject.Inject;
 
 /**
  * Bouncer between work activities and the activity used to confirm credentials before unlocking
@@ -67,14 +70,21 @@
      * @see KeyguardManager
      */
     private KeyguardManager mKgm;
+    private final BroadcastDispatcher mBroadcastDispatcher;
+
+    @Inject
+    public WorkLockActivity(BroadcastDispatcher broadcastDispatcher) {
+        super();
+        mBroadcastDispatcher = broadcastDispatcher;
+    }
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        registerReceiverAsUser(mLockEventReceiver, UserHandle.ALL,
-                new IntentFilter(Intent.ACTION_DEVICE_LOCKED_CHANGED), /* permission */ null,
-                /* scheduler */ null);
+        mBroadcastDispatcher.registerReceiver(mLockEventReceiver,
+                new IntentFilter(Intent.ACTION_DEVICE_LOCKED_CHANGED), null /* handler */,
+                UserHandle.ALL);
 
         // Once the receiver is registered, check whether anything happened between now and the time
         // when this activity was launched. If it did and the user is unlocked now, just quit.
@@ -107,9 +117,14 @@
         }
     }
 
+    @VisibleForTesting
+    protected void unregisterBroadcastReceiver() {
+        mBroadcastDispatcher.unregisterReceiver(mLockEventReceiver);
+    }
+
     @Override
     public void onDestroy() {
-        unregisterReceiver(mLockEventReceiver);
+        unregisterBroadcastReceiver();
         super.onDestroy();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/log/RichEvent.java b/packages/SystemUI/src/com/android/systemui/log/RichEvent.java
index 89b7a818..acf761ed 100644
--- a/packages/SystemUI/src/com/android/systemui/log/RichEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/log/RichEvent.java
@@ -67,7 +67,7 @@
         private B mBuilder = getBuilder();
         protected int mType = UNINITIALIZED;
         protected String mReason;
-        protected @Level int mLogLevel;
+        protected @Level int mLogLevel = VERBOSE;
 
         /**
          * Get the log-specific builder.
diff --git a/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java b/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java
index a6e10e6..f094cb9 100644
--- a/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java
+++ b/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java
@@ -120,9 +120,9 @@
     }
 
     /**
-     * @return user-readable string of the given event
+     * @return user-readable string of the given event with timestamp
      */
-    public String eventToString(Event event) {
+    public String eventToTimestampedString(Event event) {
         StringBuilder sb = new StringBuilder();
         sb.append(SysuiLog.DATE_FORMAT.format(event.getTimestamp()));
         sb.append(" ");
@@ -131,13 +131,20 @@
     }
 
     /**
+     * @return user-readable string of the given event without a timestamp
+     */
+    public String eventToString(Event event) {
+        return event.getMessage();
+    }
+
+    /**
      * only call on this method if you have the mDataLock
      */
     private void dumpTimelineLocked(PrintWriter pw) {
         pw.println("\tTimeline:");
 
         for (Event event : mTimeline) {
-            pw.println("\t" + eventToString(event));
+            pw.println("\t" + eventToTimestampedString(event));
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java b/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
index 05be425..75e260e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
@@ -19,10 +19,12 @@
 import android.content.Context;
 import android.content.res.Configuration;
 
+import com.android.systemui.broadcast.BroadcastDispatcher;
+
 import java.io.PrintWriter;
 
 public interface BasePipManager {
-    void initialize(Context context);
+    void initialize(Context context, BroadcastDispatcher broadcastDispatcher);
     void showPictureInPictureMenu();
     default void expandPip() {}
     default void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
index f1e801b..583ce67 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
@@ -26,6 +26,7 @@
 import android.os.UserManager;
 
 import com.android.systemui.SystemUI;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.statusbar.CommandQueue;
 
 import java.io.FileDescriptor;
@@ -40,13 +41,18 @@
 @Singleton
 public class PipUI extends SystemUI implements CommandQueue.Callbacks {
 
+    private final CommandQueue mCommandQueue;
     private BasePipManager mPipManager;
+    private final BroadcastDispatcher mBroadcastDispatcher;
 
     private boolean mSupportsPip;
 
     @Inject
-    public PipUI(Context context) {
+    public PipUI(Context context, CommandQueue commandQueue,
+            BroadcastDispatcher broadcastDispatcher) {
         super(context);
+        mBroadcastDispatcher = broadcastDispatcher;
+        mCommandQueue = commandQueue;
     }
 
     @Override
@@ -66,9 +72,9 @@
         mPipManager = pm.hasSystemFeature(FEATURE_LEANBACK_ONLY)
                 ? com.android.systemui.pip.tv.PipManager.getInstance()
                 : com.android.systemui.pip.phone.PipManager.getInstance();
-        mPipManager.initialize(mContext);
+        mPipManager.initialize(mContext, mBroadcastDispatcher);
 
-        getComponent(CommandQueue.class).addCallback(this);
+        mCommandQueue.addCallback(this);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 369073c..c33b8d9 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -37,6 +37,7 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.UiOffloadThread;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.pip.BasePipManager;
 import com.android.systemui.pip.PipBoundsHandler;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -200,7 +201,7 @@
     /**
      * Initializes {@link PipManager}.
      */
-    public void initialize(Context context) {
+    public void initialize(Context context, BroadcastDispatcher broadcastDispatcher) {
         mContext = context;
         mActivityManager = ActivityManager.getService();
         mActivityTaskManager = ActivityTaskManager.getService();
@@ -214,7 +215,7 @@
 
         mPipBoundsHandler = new PipBoundsHandler(context);
         mInputConsumerController = InputConsumerController.getPipInputConsumer();
-        mMediaController = new PipMediaController(context, mActivityManager);
+        mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher);
         mMenuController = new PipMenuActivityController(context, mActivityManager, mMediaController,
                 mInputConsumerController);
         mTouchHandler = new PipTouchHandler(context, mActivityManager, mActivityTaskManager,
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
index 174a7ef..e57b416 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
@@ -37,6 +37,7 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.statusbar.policy.UserInfoController;
 
 import java.util.ArrayList;
@@ -109,7 +110,8 @@
 
     private ArrayList<ActionListener> mListeners = new ArrayList<>();
 
-    public PipMediaController(Context context, IActivityManager activityManager) {
+    public PipMediaController(Context context, IActivityManager activityManager,
+            BroadcastDispatcher broadcastDispatcher) {
         mContext = context;
         mActivityManager = activityManager;
         IntentFilter mediaControlFilter = new IntentFilter();
@@ -117,7 +119,7 @@
         mediaControlFilter.addAction(ACTION_PAUSE);
         mediaControlFilter.addAction(ACTION_NEXT);
         mediaControlFilter.addAction(ACTION_PREV);
-        mContext.registerReceiver(mPlayPauseActionReceiver, mediaControlFilter);
+        broadcastDispatcher.registerReceiver(mPlayPauseActionReceiver, mediaControlFilter);
 
         createMediaActions();
         mMediaSessionManager =
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 5723afd..c452f64 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -90,7 +90,7 @@
     public static final int MESSAGE_UPDATE_ACTIONS = 4;
     public static final int MESSAGE_UPDATE_DISMISS_FRACTION = 5;
     public static final int MESSAGE_ANIMATION_ENDED = 6;
-    public static final int MESSAGE_TOUCH_EVENT = 7;
+    public static final int MESSAGE_POINTER_EVENT = 7;
 
     private static final int INITIAL_DISMISS_DELAY = 3500;
     private static final int POST_INTERACTION_DISMISS_DELAY = 2000;
@@ -165,9 +165,9 @@
                     break;
                 }
 
-                case MESSAGE_TOUCH_EVENT: {
+                case MESSAGE_POINTER_EVENT: {
                     final MotionEvent ev = (MotionEvent) msg.obj;
-                    dispatchTouchEvent(ev);
+                    dispatchPointerEvent(ev);
                     break;
                 }
             }
@@ -219,6 +219,9 @@
         updateFromIntent(getIntent());
         setTitle(R.string.pip_menu_title);
         setDisablePreviewScreenshots(true);
+
+        // Hide without an animation.
+        getWindow().setExitTransition(null);
     }
 
     @Override
@@ -269,6 +272,17 @@
         }
     }
 
+    /**
+     * Dispatch a pointer event from {@link PipTouchHandler}.
+     */
+    private void dispatchPointerEvent(MotionEvent event) {
+        if (event.isTouchEvent()) {
+            dispatchTouchEvent(event);
+        } else {
+            dispatchGenericMotionEvent(event);
+        }
+    }
+
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
         if (!mAllowTouches) {
@@ -288,8 +302,6 @@
     public void finish() {
         notifyActivityCallback(null);
         super.finish();
-        // Hide without an animation (the menu should already be invisible at this point)
-        overridePendingTransition(0, 0);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 62c59e5..b8e0b81 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -508,12 +508,12 @@
     }
 
     /**
-     * Handles touch event sent from pip input consumer.
+     * Handles a pointer event sent from pip input consumer.
      */
-    void handleTouchEvent(MotionEvent ev) {
+    void handlePointerEvent(MotionEvent ev) {
         if (mToActivityMessenger != null) {
             Message m = Message.obtain();
-            m.what = PipMenuActivity.MESSAGE_TOUCH_EVENT;
+            m.what = PipMenuActivity.MESSAGE_POINTER_EVENT;
             m.obj = ev;
             try {
                 mToActivityMessenger.send(m);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 1f36d97..f59b372 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -132,6 +132,7 @@
     private boolean mSendingHoverAccessibilityEvents;
     private boolean mMovementWithinMinimize;
     private boolean mMovementWithinDismiss;
+    private PipAccessibilityInteractionConnection mConnection;
 
     // Touch state
     private final PipTouchState mTouchState;
@@ -213,9 +214,10 @@
         // Register the listener for input consumer touch events
         inputConsumerController.setInputListener(this::handleTouchEvent);
         inputConsumerController.setRegistrationListener(this::onRegistrationChanged);
-        onRegistrationChanged(inputConsumerController.isRegistered());
 
         mPipBoundsHandler = pipBoundsHandler;
+        mConnection = new PipAccessibilityInteractionConnection(mMotionHelper,
+                this::onAccessibilityShowMenu, mHandler);
     }
 
     public void setTouchEnabled(boolean enabled) {
@@ -339,9 +341,7 @@
 
     private void onRegistrationChanged(boolean isRegistered) {
         mAccessibilityManager.setPictureInPictureActionReplacingConnection(isRegistered
-                ? new PipAccessibilityInteractionConnection(mMotionHelper,
-                        this::onAccessibilityShowMenu, mHandler) : null);
-
+                ? mConnection : null);
         if (!isRegistered && mTouchState.isUserInteracting()) {
             // If the input consumer is unregistered while the user is interacting, then we may not
             // get the final TOUCH_UP event, so clean up the dismiss target as well
@@ -409,27 +409,15 @@
             }
             case MotionEvent.ACTION_HOVER_ENTER:
             case MotionEvent.ACTION_HOVER_MOVE: {
-                if (mAccessibilityManager.isEnabled() && !mSendingHoverAccessibilityEvents) {
-                    AccessibilityEvent event = AccessibilityEvent.obtain(
-                            AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
-                    event.setImportantForAccessibility(true);
-                    event.setSourceNodeId(AccessibilityNodeInfo.ROOT_NODE_ID);
-                    event.setWindowId(
-                            AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID);
-                    mAccessibilityManager.sendAccessibilityEvent(event);
+                if (!shouldDeliverToMenu && !mSendingHoverAccessibilityEvents) {
+                    sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
                     mSendingHoverAccessibilityEvents = true;
                 }
                 break;
             }
             case MotionEvent.ACTION_HOVER_EXIT: {
-                if (mAccessibilityManager.isEnabled() && mSendingHoverAccessibilityEvents) {
-                    AccessibilityEvent event = AccessibilityEvent.obtain(
-                            AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
-                    event.setImportantForAccessibility(true);
-                    event.setSourceNodeId(AccessibilityNodeInfo.ROOT_NODE_ID);
-                    event.setWindowId(
-                            AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID);
-                    mAccessibilityManager.sendAccessibilityEvent(event);
+                if (!shouldDeliverToMenu && mSendingHoverAccessibilityEvents) {
+                    sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
                     mSendingHoverAccessibilityEvents = false;
                 }
                 break;
@@ -445,12 +433,25 @@
                 mMenuController.pokeMenu();
             }
 
-            mMenuController.handleTouchEvent(cloneEvent);
+            mMenuController.handlePointerEvent(cloneEvent);
         }
 
         return true;
     }
 
+    private void sendAccessibilityHoverEvent(int type) {
+        if (!mAccessibilityManager.isEnabled()) {
+            return;
+        }
+
+        AccessibilityEvent event = AccessibilityEvent.obtain(type);
+        event.setImportantForAccessibility(true);
+        event.setSourceNodeId(AccessibilityNodeInfo.ROOT_NODE_ID);
+        event.setWindowId(
+                AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID);
+        mAccessibilityManager.sendAccessibilityEvent(event);
+    }
+
     /**
      * Updates the appearance of the menu and scrim on top of the PiP while dismissing.
      */
@@ -523,6 +524,10 @@
      * Sets the menu visibility.
      */
     private void setMenuState(int menuState, boolean resize) {
+        if (mMenuState == menuState && !resize) {
+            return;
+        }
+
         if (menuState == MENU_STATE_FULL && mMenuState != MENU_STATE_FULL) {
             // Save the current snap fraction and if we do not drag or move the PiP, then
             // we store back to this snap fraction.  Otherwise, we'll reset the snap
@@ -571,6 +576,9 @@
         }
         mMenuState = menuState;
         updateMovementBounds(menuState);
+        // If pip menu has dismissed, we should register the A11y ActionReplacingConnection for pip
+        // as well, or it can't handle a11y focus and pip menu can't perform any action.
+        onRegistrationChanged(menuState == MENU_STATE_NONE);
         if (menuState != MENU_STATE_CLOSE) {
             MetricsLoggerWrapper.logPictureInPictureMenuVisible(mContext, menuState == MENU_STATE_FULL);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 81d6973..195fca8 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -48,6 +48,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.UiOffloadThread;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.pip.BasePipManager;
 import com.android.systemui.pip.PipBoundsHandler;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -227,7 +228,7 @@
     /**
      * Initializes {@link PipManager}.
      */
-    public void initialize(Context context) {
+    public void initialize(Context context, BroadcastDispatcher broadcastDispatcher) {
         if (mInitialized) {
             return;
         }
@@ -238,8 +239,8 @@
         ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_MEDIA_RESOURCE_GRANTED);
-        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, intentFilter,
-                null, null);
+        broadcastDispatcher.registerReceiver(mBroadcastReceiver, intentFilter,
+                null /* handler */, UserHandle.ALL);
 
         if (sSettingsPackageAndClassNamePairList == null) {
             String[] settings = mContext.getResources().getStringArray(
@@ -286,7 +287,7 @@
             Log.e(TAG, "Failed to register pinned stack listener", e);
         }
 
-        mPipNotification = new PipNotification(context);
+        mPipNotification = new PipNotification(context, broadcastDispatcher);
     }
 
     private void loadConfigurationsAndApply(Configuration newConfig) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
index d50f294e4..ca15131 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
@@ -34,6 +34,7 @@
 
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.util.NotificationChannels;
 
 /**
@@ -143,7 +144,7 @@
         }
     };
 
-    public PipNotification(Context context) {
+    public PipNotification(Context context, BroadcastDispatcher broadcastDispatcher) {
         mNotificationManager = (NotificationManager) context.getSystemService(
                 Context.NOTIFICATION_SERVICE);
 
@@ -161,7 +162,7 @@
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(ACTION_MENU);
         intentFilter.addAction(ACTION_CLOSE);
-        context.registerReceiver(mEventReceiver, intentFilter);
+        broadcastDispatcher.registerReceiver(mEventReceiver, intentFilter);
 
         onConfigurationChanged(context);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 98f0b2a..f60d9db 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -55,7 +55,11 @@
 import java.util.concurrent.Future;
 
 import javax.inject.Inject;
+import javax.inject.Singleton;
 
+import dagger.Lazy;
+
+@Singleton
 public class PowerUI extends SystemUI {
 
     static final String TAG = "PowerUI";
@@ -101,11 +105,14 @@
     private IThermalEventListener mSkinThermalEventListener;
     private IThermalEventListener mUsbThermalEventListener;
     private final BroadcastDispatcher mBroadcastDispatcher;
+    private final Lazy<StatusBar> mStatusBarLazy;
 
     @Inject
-    public PowerUI(Context context, BroadcastDispatcher broadcastDispatcher) {
+    public PowerUI(Context context, BroadcastDispatcher broadcastDispatcher,
+            Lazy<StatusBar> statusBarLazy) {
         super(context);
         mBroadcastDispatcher = broadcastDispatcher;
+        mStatusBarLazy = statusBarLazy;
     }
 
     public void start() {
@@ -663,8 +670,7 @@
             int status = temp.getStatus();
 
             if (status >= Temperature.THROTTLING_EMERGENCY) {
-                StatusBar statusBar = getComponent(StatusBar.class);
-                if (statusBar != null && !statusBar.isDeviceInVrMode()) {
+                if (!mStatusBarLazy.get().isDeviceInVrMode()) {
                     mWarnings.showHighTemperatureWarning();
                     Slog.d(TAG, "SkinThermalEventListener: notifyThrottling was called "
                             + ", current skin status = " + status
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index 22fb4c0..d592492 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -22,7 +22,11 @@
 import android.content.Context
 import android.content.Intent
 import android.content.IntentFilter
-import android.os.*
+import android.os.Handler
+import android.os.Looper
+import android.os.Message
+import android.os.UserHandle
+import android.os.UserManager
 import android.provider.DeviceConfig
 import com.android.internal.annotations.VisibleForTesting
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags
@@ -30,6 +34,7 @@
 import com.android.systemui.R
 import com.android.systemui.appops.AppOpItem
 import com.android.systemui.appops.AppOpsController
+import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.dagger.qualifiers.BgHandler
 import com.android.systemui.dagger.qualifiers.MainHandler
 import java.io.FileDescriptor
@@ -43,10 +48,11 @@
 
 @Singleton
 class PrivacyItemController @Inject constructor(
-    val context: Context,
+    private val context: Context,
     private val appOpsController: AppOpsController,
     @MainHandler private val uiHandler: Handler,
-    @BgHandler private val bgHandler: Handler
+    @BgHandler private val bgHandler: Handler,
+    private val broadcastDispatcher: BroadcastDispatcher
 ) : Dumpable {
 
     @VisibleForTesting
@@ -134,15 +140,15 @@
     }
 
     private fun unregisterReceiver() {
-        context.unregisterReceiver(userSwitcherReceiver)
+        broadcastDispatcher.unregisterReceiver(userSwitcherReceiver)
     }
 
     private fun registerReceiver() {
-        context.registerReceiverAsUser(userSwitcherReceiver, UserHandle.ALL, IntentFilter().apply {
+        broadcastDispatcher.registerReceiver(userSwitcherReceiver, IntentFilter().apply {
             intents.forEach {
                 addAction(it)
             }
-        }, null, null)
+        }, null /* handler */, UserHandle.ALL)
     }
 
     private fun update(updateUsers: Boolean) {
@@ -248,20 +254,20 @@
         }
     }
 
-    override fun dump(fd: FileDescriptor?, pw: PrintWriter?, args: Array<out String>?) {
-        pw?.println("PrivacyItemController state:")
-        pw?.println("  Listening: $listening")
-        pw?.println("  Current user ids: $currentUserIds")
-        pw?.println("  Privacy Items:")
+    override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+        pw.println("PrivacyItemController state:")
+        pw.println("  Listening: $listening")
+        pw.println("  Current user ids: $currentUserIds")
+        pw.println("  Privacy Items:")
         privacyList.forEach {
-            pw?.print("    ")
-            pw?.println(it.toString())
+            pw.print("    ")
+            pw.println(it.toString())
         }
-        pw?.println("  Callbacks:")
+        pw.println("  Callbacks:")
         callbacks.forEach {
             it.get()?.let {
-                pw?.print("    ")
-                pw?.println(it.toString())
+                pw.print("    ")
+                pw.println(it.toString())
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index a267bbb..a0ea7fa 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -14,7 +14,6 @@
 
 package com.android.systemui.qs;
 
-import android.provider.Settings;
 import android.util.Log;
 import android.view.View;
 import android.view.View.OnAttachStateChangeListener;
@@ -31,6 +30,7 @@
 import com.android.systemui.qs.TouchAnimator.Listener;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
+import com.android.systemui.util.Utils;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -270,9 +270,7 @@
         }
 
 
-        int flag = Settings.System.getInt(mQsPanel.getContext().getContentResolver(),
-                "qs_media_player", 0);
-        if (flag == 1) {
+        if (Utils.useQsMediaPlayer(mQsPanel.getContext())) {
             View qsMediaView = mQsPanel.getMediaPanel();
             View qqsMediaView = mQuickQsPanel.getMediaPlayer().getView();
             translationXBuilder.addFloat(qsMediaView, "alpha", 0, 1);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 496aa0e..60d30da 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -38,7 +38,6 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.statusbar.CommandQueue;
@@ -169,8 +168,7 @@
             setupDetailHeader(adapter);
             if (toggleQs && !mFullyExpanded) {
                 mTriggeredExpand = true;
-                SysUiServiceProvider.getComponent(mContext, CommandQueue.class)
-                        .animateExpandSettingsPanel(null);
+                Dependency.get(CommandQueue.class).animateExpandSettingsPanel(null);
             } else {
                 mTriggeredExpand = false;
             }
@@ -181,8 +179,7 @@
             x = mOpenX;
             y = mOpenY;
             if (toggleQs && mTriggeredExpand) {
-                SysUiServiceProvider.getComponent(mContext, CommandQueue.class)
-                        .animateCollapsePanels();
+                Dependency.get(CommandQueue.class).animateCollapsePanels();
                 mTriggeredExpand = false;
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 0a3b43a..ccc836f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -38,7 +38,6 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.R.id;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.customize.QSCustomizer;
@@ -97,11 +96,10 @@
             InjectionInflationController injectionInflater,
             Context context,
             QSTileHost qsTileHost,
-            StatusBarStateController statusBarStateController) {
+            StatusBarStateController statusBarStateController, CommandQueue commandQueue) {
         mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
         mInjectionInflater = injectionInflater;
-        SysUiServiceProvider.getComponent(context, CommandQueue.class)
-                .observe(getLifecycle(), this);
+        commandQueue.observe(getLifecycle(), this);
         mHost = qsTileHost;
         mStatusBarStateController = statusBarStateController;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
index af418f6..6949640 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
@@ -33,6 +33,7 @@
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
 import android.media.session.PlaybackState;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -50,7 +51,6 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.statusbar.MediaTransferManager;
 
 /**
  * Single media player for carousel in QSPanel
@@ -101,6 +101,12 @@
         mToken = token;
         mController = new MediaController(mContext, token);
         MediaMetadata mMediaMetadata = mController.getMetadata();
+
+        if (mMediaMetadata == null) {
+            Log.e(TAG, "Media metadata was null");
+            return;
+        }
+
         Notification.Builder builder = Notification.Builder.recoverBuilder(mContext, notif);
 
         // Album art
@@ -151,18 +157,17 @@
         // Album name
         TextView albumName = headerView.findViewById(com.android.internal.R.id.header_text);
         String albumString = mMediaMetadata.getString(MediaMetadata.METADATA_KEY_ALBUM);
-        if (!albumString.isEmpty()) {
+        if (TextUtils.isEmpty(albumString)) {
+            albumName.setVisibility(View.GONE);
+            separator.setVisibility(View.GONE);
+        } else {
             albumName.setText(albumString);
             albumName.setTextColor(iconColor);
             albumName.setVisibility(View.VISIBLE);
             separator.setVisibility(View.VISIBLE);
-        } else {
-            albumName.setVisibility(View.GONE);
-            separator.setVisibility(View.GONE);
         }
 
         // Transfer chip
-        MediaTransferManager mediaTransferManager = new MediaTransferManager(mContext);
         View transferBackgroundView = headerView.findViewById(
                 com.android.internal.R.id.media_seamless);
         LinearLayout viewLayout = (LinearLayout) transferBackgroundView;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 2060059..cac9025 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -18,6 +18,7 @@
 
 import static com.android.systemui.qs.tileimpl.QSTileImpl.getColorForState;
 import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
+import static com.android.systemui.util.Utils.useQsMediaPlayer;
 
 import android.annotation.Nullable;
 import android.content.ComponentName;
@@ -49,6 +50,7 @@
 import com.android.systemui.DumpController;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTileView;
@@ -124,12 +126,13 @@
     }
 
     public QSPanel(Context context, AttributeSet attrs, DumpController dumpController) {
-        this(context, attrs, dumpController, null);
+        this(context, attrs, dumpController, null, Dependency.get(BroadcastDispatcher.class));
     }
 
     @Inject
     public QSPanel(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
-            DumpController dumpController, PluginManager pluginManager) {
+            DumpController dumpController, PluginManager pluginManager,
+            BroadcastDispatcher broadcastDispatcher) {
         super(context, attrs);
         mContext = context;
 
@@ -150,8 +153,7 @@
         addDivider();
 
         // Add media carousel
-        int flag = Settings.System.getInt(context.getContentResolver(), "qs_media_player", 0);
-        if (flag == 1) {
+        if (useQsMediaPlayer(context)) {
             HorizontalScrollView mediaScrollView = new HorizontalScrollView(mContext);
             mediaScrollView.setHorizontalScrollBarEnabled(false);
             int playerHeight = (int) getResources().getDimension(R.dimen.qs_media_height);
@@ -166,6 +168,7 @@
             mMediaCarousel = new LinearLayout(mContext);
             mMediaCarousel.setOrientation(LinearLayout.HORIZONTAL);
             mediaScrollView.addView(mMediaCarousel, lpCarousel);
+            mediaScrollView.setVisibility(View.GONE);
         } else {
             mMediaCarousel = null;
         }
@@ -176,7 +179,7 @@
         updateResources();
 
         mBrightnessController = new BrightnessController(getContext(),
-                findViewById(R.id.brightness_slider));
+                findViewById(R.id.brightness_slider), broadcastDispatcher);
         mDumpController = dumpController;
         mPluginManager = pluginManager;
         if (mPluginManager != null && Settings.System.getInt(
@@ -200,8 +203,7 @@
      */
     public void addMediaSession(MediaSession.Token token, Icon icon, int iconColor, int bgColor,
             View actionsContainer, StatusBarNotification notif) {
-        int flag = Settings.System.getInt(mContext.getContentResolver(), "qs_media_player", 0);
-        if (flag != 1) {
+        if (!useQsMediaPlayer(mContext)) {
             // Shouldn't happen, but just in case
             Log.e(TAG, "Tried to add media session without player!");
             return;
@@ -239,6 +241,7 @@
             } else {
                 mMediaCarousel.addView(player.getView(), lp); // add at end
             }
+            mMediaPlayers.add(player);
         } else if (player.isPlaying()) {
             // move it to the front
             mMediaCarousel.removeView(player.getView());
@@ -248,7 +251,10 @@
         Log.d(TAG, "setting player session");
         player.setMediaSession(token, icon, iconColor, bgColor, actionsContainer,
                 notif.getNotification());
-        mMediaPlayers.add(player);
+
+        if (mMediaPlayers.size() > 0) {
+            ((View) mMediaCarousel.getParent()).setVisibility(View.VISIBLE);
+        }
     }
 
     protected View getMediaPanel() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index b395c3c..6d434b1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -34,6 +34,7 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.BgLooper;
 import com.android.systemui.dagger.qualifiers.MainHandler;
 import com.android.systemui.plugins.PluginListener;
@@ -80,6 +81,7 @@
     private final TunerService mTunerService;
     private final PluginManager mPluginManager;
     private final DumpController mDumpController;
+    private final BroadcastDispatcher mBroadcastDispatcher;
 
     private final List<Callback> mCallbacks = new ArrayList<>();
     private AutoTileManager mAutoTiles;
@@ -99,14 +101,16 @@
             PluginManager pluginManager,
             TunerService tunerService,
             Provider<AutoTileManager> autoTiles,
-            DumpController dumpController) {
+            DumpController dumpController,
+            BroadcastDispatcher broadcastDispatcher) {
         mIconController = iconController;
         mContext = context;
         mTunerService = tunerService;
         mPluginManager = pluginManager;
         mDumpController = dumpController;
+        mBroadcastDispatcher = broadcastDispatcher;
 
-        mServices = new TileServices(this, bgLooper);
+        mServices = new TileServices(this, bgLooper, mBroadcastDispatcher);
 
         defaultFactory.setHost(this);
         mQsFactories.add(defaultFactory);
@@ -334,7 +338,8 @@
                 Intent intent = new Intent().setComponent(component);
                 TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(),
                         mContext, mServices, new Tile(), intent,
-                        new UserHandle(ActivityManager.getCurrentUser()));
+                        new UserHandle(ActivityManager.getCurrentUser()),
+                        mBroadcastDispatcher);
                 lifecycleManager.onStopListening();
                 lifecycleManager.onTileRemoved();
                 TileLifecycleManager.setTileAdded(mContext, component, false);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
index ae66cd5..3ec71ac 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
@@ -84,6 +84,11 @@
         mController = new MediaController(mContext, token);
         MediaMetadata mMediaMetadata = mController.getMetadata();
 
+        if (mMediaMetadata == null) {
+            Log.e(TAG, "Media metadata was null");
+            return;
+        }
+
         // Album art
         addAlbumArtBackground(mMediaMetadata, bgColor);
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index dcd4633..94a1cf0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Rect;
-import android.provider.Settings;
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.View;
@@ -36,6 +35,7 @@
 import com.android.systemui.qs.customize.QSCustomizer;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
+import com.android.systemui.util.Utils;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -72,8 +72,7 @@
             removeView((View) mTileLayout);
         }
 
-        int flag = Settings.System.getInt(context.getContentResolver(), "qs_media_player", 0);
-        if (flag == 1) {
+        if (Utils.useQsMediaPlayer(context)) {
             LinearLayout mHorizontalLinearLayout = new LinearLayout(mContext);
             mHorizontalLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
             mHorizontalLinearLayout.setClipChildren(false);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 592e388..19af235 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -17,6 +17,7 @@
 import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
 
 import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
+import static com.android.systemui.util.Utils.useQsMediaPlayer;
 
 import android.annotation.ColorInt;
 import android.app.ActivityManager;
@@ -60,6 +61,7 @@
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.DualToneHandler;
 import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
@@ -69,6 +71,7 @@
 import com.android.systemui.privacy.PrivacyItemController;
 import com.android.systemui.privacy.PrivacyItemControllerKt;
 import com.android.systemui.qs.QSDetail.Callback;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.PhoneStatusBarView;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
@@ -123,6 +126,7 @@
     private TouchAnimator mHeaderTextContainerAlphaAnimator;
     private TouchAnimator mPrivacyChipAlphaAnimator;
     private DualToneHandler mDualToneHandler;
+    private final CommandQueue mCommandQueue;
 
     private View mSystemIconsView;
     private View mQuickQsStatusIcons;
@@ -147,6 +151,7 @@
     private boolean mPermissionsHubEnabled;
 
     private PrivacyItemController mPrivacyItemController;
+    private BroadcastDispatcher mBroadcastDispatcher;
 
     private final BroadcastReceiver mRingerReceiver = new BroadcastReceiver() {
         @Override
@@ -185,7 +190,8 @@
     public QuickStatusBarHeader(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
             NextAlarmController nextAlarmController, ZenModeController zenModeController,
             StatusBarIconController statusBarIconController,
-            ActivityStarter activityStarter, PrivacyItemController privacyItemController) {
+            ActivityStarter activityStarter, PrivacyItemController privacyItemController,
+            CommandQueue commandQueue, BroadcastDispatcher broadcastDispatcher) {
         super(context, attrs);
         mAlarmController = nextAlarmController;
         mZenController = zenModeController;
@@ -194,6 +200,8 @@
         mPrivacyItemController = privacyItemController;
         mDualToneHandler = new DualToneHandler(
                 new ContextThemeWrapper(context, R.style.QSHeaderTheme));
+        mBroadcastDispatcher = broadcastDispatcher;
+        mCommandQueue = commandQueue;
     }
 
     @Override
@@ -207,7 +215,7 @@
         // Ignore privacy icons because they show in the space above QQS
         iconContainer.addIgnoredSlots(getIgnoredIconSlots());
         iconContainer.setShouldRestrictIcons(false);
-        mIconManager = new TintedIconManager(iconContainer);
+        mIconManager = new TintedIconManager(iconContainer, mCommandQueue);
 
         // Views corresponding to the header info section (e.g. ringer and next alarm).
         mHeaderTextContainerView = findViewById(R.id.header_text_container);
@@ -393,11 +401,10 @@
 
         FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
 
-        int flag = Settings.System.getInt(mContext.getContentResolver(), "qs_media_player", 0);
         if (mQsDisabled) {
             lp.height = resources.getDimensionPixelSize(
                     com.android.internal.R.dimen.quick_qs_offset_height);
-        } else if (flag == 1) {
+        } else if (useQsMediaPlayer(mContext)) {
             lp.height = Math.max(getMinimumHeight(),
                     resources.getDimensionPixelSize(
                             com.android.internal.R.dimen.quick_qs_total_height_with_media));
@@ -547,14 +554,14 @@
         if (listening) {
             mZenController.addCallback(this);
             mAlarmController.addCallback(this);
-            mContext.registerReceiver(mRingerReceiver,
+            mBroadcastDispatcher.registerReceiver(mRingerReceiver,
                     new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
             mPrivacyItemController.addCallback(mPICCallback);
         } else {
             mZenController.removeCallback(this);
             mAlarmController.removeCallback(this);
             mPrivacyItemController.removeCallback(mPICCallback);
-            mContext.unregisterReceiver(mRingerReceiver);
+            mBroadcastDispatcher.unregisterReceiver(mRingerReceiver);
             mPrivacyChipLogged = false;
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index f59e0c2..9261412 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -38,6 +38,8 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.systemui.broadcast.BroadcastDispatcher;
+
 import java.util.Objects;
 import java.util.Set;
 
@@ -72,6 +74,7 @@
     private final UserHandle mUser;
     private final IBinder mToken = new Binder();
     private final PackageManagerAdapter mPackageManagerAdapter;
+    private final BroadcastDispatcher mBroadcastDispatcher;
 
     private Set<Integer> mQueuedMessages = new ArraySet<>();
     private QSTileServiceWrapper mWrapper;
@@ -88,13 +91,15 @@
     private boolean mIsBound;
 
     public TileLifecycleManager(Handler handler, Context context, IQSService service, Tile tile,
-            Intent intent, UserHandle user) {
-        this(handler, context, service, tile, intent, user, new PackageManagerAdapter(context));
+            Intent intent, UserHandle user, BroadcastDispatcher broadcastDispatcher) {
+        this(handler, context, service, tile, intent, user, new PackageManagerAdapter(context),
+                broadcastDispatcher);
     }
 
     @VisibleForTesting
     TileLifecycleManager(Handler handler, Context context, IQSService service, Tile tile,
-            Intent intent, UserHandle user, PackageManagerAdapter packageManagerAdapter) {
+            Intent intent, UserHandle user, PackageManagerAdapter packageManagerAdapter,
+            BroadcastDispatcher broadcastDispatcher) {
         mContext = context;
         mHandler = handler;
         mIntent = intent;
@@ -102,6 +107,7 @@
         mIntent.putExtra(TileService.EXTRA_TOKEN, mToken);
         mUser = user;
         mPackageManagerAdapter = packageManagerAdapter;
+        mBroadcastDispatcher = broadcastDispatcher;
         if (DEBUG) Log.d(TAG, "Creating " + mIntent + " " + mUser);
     }
 
@@ -306,13 +312,14 @@
         filter.addDataScheme("package");
         mContext.registerReceiverAsUser(this, mUser, filter, null, mHandler);
         filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
-        mContext.registerReceiverAsUser(this, mUser, filter, null, mHandler);
+        mBroadcastDispatcher.registerReceiver(this, filter, mHandler, mUser);
         mReceiverRegistered = true;
     }
 
     private void stopPackageListening() {
         if (DEBUG) Log.d(TAG, "stopPackageListening");
         mContext.unregisterReceiver(this);
+        mBroadcastDispatcher.unregisterReceiver(this);
         mReceiverRegistered = false;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
index 0b4e648..1902d65 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -34,6 +34,7 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener;
 
 import java.util.List;
@@ -72,10 +73,10 @@
     private boolean mStarted = false;
 
     TileServiceManager(TileServices tileServices, Handler handler, ComponentName component,
-            Tile tile) {
+            Tile tile, BroadcastDispatcher broadcastDispatcher) {
         this(tileServices, handler, new TileLifecycleManager(handler,
                 tileServices.getContext(), tileServices, tile, new Intent().setComponent(component),
-                new UserHandle(ActivityManager.getCurrentUser())));
+                new UserHandle(ActivityManager.getCurrentUser()), broadcastDispatcher));
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index 13cfa78..db7c6ad 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -37,6 +37,7 @@
 
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.systemui.Dependency;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -60,13 +61,15 @@
     private final Handler mHandler;
     private final Handler mMainHandler;
     private final QSTileHost mHost;
+    private final BroadcastDispatcher mBroadcastDispatcher;
 
     private int mMaxBound = DEFAULT_MAX_BOUND;
 
-    public TileServices(QSTileHost host, Looper looper) {
+    public TileServices(QSTileHost host, Looper looper, BroadcastDispatcher broadcastDispatcher) {
         mHost = host;
         mContext = mHost.getContext();
-        mContext.registerReceiver(mRequestListeningReceiver,
+        mBroadcastDispatcher = broadcastDispatcher;
+        mBroadcastDispatcher.registerReceiver(mRequestListeningReceiver,
                 new IntentFilter(TileService.ACTION_REQUEST_LISTENING));
         mHandler = new Handler(looper);
         mMainHandler = new Handler(Looper.getMainLooper());
@@ -82,7 +85,8 @@
 
     public TileServiceManager getTileWrapper(CustomTile tile) {
         ComponentName component = tile.getComponent();
-        TileServiceManager service = onCreateTileService(component, tile.getQsTile());
+        TileServiceManager service = onCreateTileService(component, tile.getQsTile(),
+                mBroadcastDispatcher);
         synchronized (mServices) {
             mServices.put(tile, service);
             mTiles.put(component, tile);
@@ -93,8 +97,10 @@
         return service;
     }
 
-    protected TileServiceManager onCreateTileService(ComponentName component, Tile tile) {
-        return new TileServiceManager(this, mHandler, component, tile);
+    protected TileServiceManager onCreateTileService(ComponentName component, Tile tile,
+            BroadcastDispatcher broadcastDispatcher) {
+        return new TileServiceManager(this, mHandler, component, tile,
+                broadcastDispatcher);
     }
 
     public void freeService(CustomTile tile, TileServiceManager service) {
@@ -323,7 +329,7 @@
     public void destroy() {
         synchronized (mServices) {
             mServices.values().forEach(service -> service.handleDestroy());
-            mContext.unregisterReceiver(mRequestListeningReceiver);
+            mBroadcastDispatcher.unregisterReceiver(mRequestListeningReceiver);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 1c8e451..9a33c8c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -145,7 +145,7 @@
                 return mBluetoothTileProvider.get();
             case "controls":
                 if (Settings.System.getInt(mHost.getContext().getContentResolver(),
-                        "qs_controls_tile_enabled", 0) == 1) {
+                        "npv_plugin_flag", 0) == 3) {
                     return mControlsTileProvider.get();
                 } else return null;
             case "cell":
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index 19e20a9..da74663 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -33,6 +33,7 @@
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.qs.GlobalSetting;
@@ -46,13 +47,16 @@
     private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_airplane);
     private final GlobalSetting mSetting;
     private final ActivityStarter mActivityStarter;
+    private final BroadcastDispatcher mBroadcastDispatcher;
 
     private boolean mListening;
 
     @Inject
-    public AirplaneModeTile(QSHost host, ActivityStarter activityStarter) {
+    public AirplaneModeTile(QSHost host, ActivityStarter activityStarter,
+            BroadcastDispatcher broadcastDispatcher) {
         super(host);
         mActivityStarter = activityStarter;
+        mBroadcastDispatcher = broadcastDispatcher;
 
         mSetting = new GlobalSetting(mContext, mHandler, Global.AIRPLANE_MODE_ON) {
             @Override
@@ -133,9 +137,9 @@
         if (listening) {
             final IntentFilter filter = new IntentFilter();
             filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-            mContext.registerReceiver(mReceiver, filter);
+            mBroadcastDispatcher.registerReceiver(mReceiver, filter);
         } else {
-            mContext.unregisterReceiver(mReceiver);
+            mBroadcastDispatcher.unregisterReceiver(mReceiver);
         }
         mSetting.setListening(listening);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ControlsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ControlsTile.java
index 0a59618..39ae66e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ControlsTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ControlsTile.java
@@ -22,11 +22,11 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.LinearLayout;
+import android.widget.FrameLayout;
 
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.HomeControlsPlugin;
+import com.android.systemui.plugins.NPVPlugin;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
@@ -44,7 +44,7 @@
     private ControlsDetailAdapter mDetailAdapter;
     private final ActivityStarter mActivityStarter;
     private PluginManager mPluginManager;
-    private HomeControlsPlugin mPlugin;
+    private NPVPlugin mPlugin;
     private Intent mHomeAppIntent;
 
     @Inject
@@ -81,7 +81,7 @@
     public void setDetailListening(boolean listening) {
         if (mPlugin == null) return;
 
-        mPlugin.setVisible(listening);
+        mPlugin.setListening(listening);
     }
 
     @Override
@@ -142,7 +142,7 @@
 
     private class ControlsDetailAdapter implements DetailAdapter {
         private View mDetailView;
-        protected LinearLayout mHomeControlsLayout;
+        protected FrameLayout mHomeControlsLayout;
 
         public CharSequence getTitle() {
             return "Controls";
@@ -157,24 +157,30 @@
         }
 
         public View createDetailView(Context context, View convertView, final ViewGroup parent) {
-            mHomeControlsLayout = (LinearLayout) LayoutInflater.from(context).inflate(
-                R.layout.home_controls, parent, false);
+            if (convertView != null) return convertView;
+
+            mHomeControlsLayout = (FrameLayout) LayoutInflater.from(context).inflate(
+                    R.layout.home_controls, parent, false);
             mHomeControlsLayout.setVisibility(View.VISIBLE);
+            parent.addView(mHomeControlsLayout);
+
             mPluginManager.addPluginListener(
-                    new PluginListener<HomeControlsPlugin>() {
+                    new PluginListener<NPVPlugin>() {
                         @Override
-                        public void onPluginConnected(HomeControlsPlugin plugin,
+                        public void onPluginConnected(NPVPlugin plugin,
                                                       Context pluginContext) {
                             mPlugin = plugin;
-                            mPlugin.sendParentGroup(mHomeControlsLayout);
-                            mPlugin.setVisible(true);
+                            mPlugin.attachToRoot(mHomeControlsLayout);
+                            mPlugin.setListening(true);
                         }
 
                         @Override
-                        public void onPluginDisconnected(HomeControlsPlugin plugin) {
+                        public void onPluginDisconnected(NPVPlugin plugin) {
+                            mPlugin.setListening(false);
+                            mHomeControlsLayout.removeAllViews();
 
                         }
-                    }, HomeControlsPlugin.class, false);
+                    }, NPVPlugin.class, false);
             return mHomeControlsLayout;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 869fa6b..52d1a5b3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -52,6 +52,7 @@
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.SysUIToast;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
@@ -78,6 +79,7 @@
     private final ZenModeController mController;
     private final DndDetailAdapter mDetailAdapter;
     private final ActivityStarter mActivityStarter;
+    private final BroadcastDispatcher mBroadcastDispatcher;
 
     private boolean mListening;
     private boolean mShowingDetail;
@@ -85,12 +87,13 @@
 
     @Inject
     public DndTile(QSHost host, ZenModeController zenModeController,
-            ActivityStarter activityStarter) {
+            ActivityStarter activityStarter, BroadcastDispatcher broadcastDispatcher) {
         super(host);
         mController = zenModeController;
         mActivityStarter = activityStarter;
         mDetailAdapter = new DndDetailAdapter();
-        mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_SET_VISIBLE));
+        mBroadcastDispatcher = broadcastDispatcher;
+        broadcastDispatcher.registerReceiver(mReceiver, new IntentFilter(ACTION_SET_VISIBLE));
         mReceiverRegistered = true;
         mController.observe(getLifecycle(), mZenCallback);
     }
@@ -99,7 +102,7 @@
     protected void handleDestroy() {
         super.handleDestroy();
         if (mReceiverRegistered) {
-            mContext.unregisterReceiver(mReceiver);
+            mBroadcastDispatcher.unregisterReceiver(mReceiver);
             mReceiverRegistered = false;
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
index 476a239..8bbfd24 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
@@ -29,6 +29,7 @@
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
@@ -39,12 +40,14 @@
 public class NfcTile extends QSTileImpl<BooleanState> {
 
     private NfcAdapter mAdapter;
+    private BroadcastDispatcher mBroadcastDispatcher;
 
     private boolean mListening;
 
     @Inject
-    public NfcTile(QSHost host) {
+    public NfcTile(QSHost host, BroadcastDispatcher broadcastDispatcher) {
         super(host);
+        mBroadcastDispatcher = broadcastDispatcher;
     }
 
     @Override
@@ -56,10 +59,10 @@
     public void handleSetListening(boolean listening) {
         mListening = listening;
         if (mListening) {
-            mContext.registerReceiver(mNfcReceiver,
+            mBroadcastDispatcher.registerReceiver(mNfcReceiver,
                     new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED));
         } else {
-            mContext.unregisterReceiver(mNfcReceiver);
+            mBroadcastDispatcher.unregisterReceiver(mNfcReceiver);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
index 958695d..7f11e56 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
@@ -20,6 +20,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.trust.TrustManager;
 import android.content.Context;
@@ -40,12 +41,22 @@
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.phone.StatusBar;
 
+import java.util.Optional;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import dagger.Lazy;
+
 /**
  * An implementation of the Recents interface which proxies to the OverviewProxyService.
  */
+@Singleton
 public class OverviewProxyRecentsImpl implements RecentsImplementation {
 
     private final static String TAG = "OverviewProxyRecentsImpl";
+    @Nullable
+    private final Lazy<StatusBar> mStatusBarLazy;
 
     private SysUiServiceProvider mSysUiServiceProvider;
     private Context mContext;
@@ -53,6 +64,12 @@
     private TrustManager mTrustManager;
     private OverviewProxyService mOverviewProxyService;
 
+    @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
+    @Inject
+    public OverviewProxyRecentsImpl(Optional<Lazy<StatusBar>> statusBarLazy) {
+        mStatusBarLazy = statusBarLazy.orElse(null);
+    }
+
     @Override
     public void onStart(Context context, SysUiServiceProvider sysUiServiceProvider) {
         mContext = context;
@@ -107,9 +124,8 @@
                 }
             };
             // Preload only if device for current user is unlocked
-            final StatusBar statusBar = mSysUiServiceProvider.getComponent(StatusBar.class);
-            if (statusBar != null && statusBar.isKeyguardShowing()) {
-                statusBar.executeRunnableDismissingKeyguard(() -> {
+            if (mStatusBarLazy != null && mStatusBarLazy.get().isKeyguardShowing()) {
+                mStatusBarLazy.get().executeRunnableDismissingKeyguard(() -> {
                         // Flush trustmanager before checking device locked per user
                         mTrustManager.reportKeyguardShowingChanged();
                         mHandler.post(toggleRecents);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 0a8264b..a8ecc12 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -29,23 +29,27 @@
 import java.io.PrintWriter;
 
 import javax.inject.Inject;
+import javax.inject.Singleton;
 
 /**
  * A proxy to a Recents implementation.
  */
+@Singleton
 public class Recents extends SystemUI implements CommandQueue.Callbacks {
 
     private final RecentsImplementation mImpl;
+    private final CommandQueue mCommandQueue;
 
     @Inject
-    public Recents(Context context, RecentsImplementation impl) {
+    public Recents(Context context, RecentsImplementation impl, CommandQueue commandQueue) {
         super(context);
         mImpl = impl;
+        mCommandQueue = commandQueue;
     }
 
     @Override
     public void start() {
-        getComponent(CommandQueue.class).addCallback(this);
+        mCommandQueue.addCallback(this);
         putComponent(Recents.class, this);
         mImpl.onStart(mContext, this);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
index 3efed3f..8cd17e9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
@@ -23,7 +23,10 @@
 
 import java.io.PrintWriter;
 
-interface RecentsImplementation {
+/**
+ * API for creating a Recents view.
+ */
+public interface RecentsImplementation {
     default void onStart(Context context, SysUiServiceProvider sysUiServiceProvider) {}
     default void onBootCompleted() {}
     default void onAppTransitionFinished() {}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsModule.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsModule.java
index 5555285..f57bfad 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsModule.java
@@ -19,35 +19,53 @@
 import android.content.Context;
 
 import com.android.systemui.R;
+import com.android.systemui.dagger.ContextComponentHelper;
 
+import dagger.Binds;
 import dagger.Module;
 import dagger.Provides;
+import dagger.multibindings.ClassKey;
+import dagger.multibindings.IntoMap;
 
 /**
  * Dagger injection module for {@link RecentsImplementation}
  */
 @Module
-public class RecentsModule {
+public abstract class RecentsModule {
+
     /**
      * @return The {@link RecentsImplementation} from the config.
      */
     @Provides
-    public RecentsImplementation provideRecentsImpl(Context context) {
+    public static RecentsImplementation provideRecentsImpl(Context context,
+            ContextComponentHelper componentHelper) {
         final String clsName = context.getString(R.string.config_recentsComponent);
         if (clsName == null || clsName.length() == 0) {
             throw new RuntimeException("No recents component configured", null);
         }
-        Class<?> cls = null;
-        try {
-            cls = context.getClassLoader().loadClass(clsName);
-        } catch (Throwable t) {
-            throw new RuntimeException("Error loading recents component: " + clsName, t);
+        RecentsImplementation impl = componentHelper.resolveRecents(clsName);
+
+        if (impl == null) {
+            Class<?> cls = null;
+            try {
+                cls = context.getClassLoader().loadClass(clsName);
+            } catch (Throwable t) {
+                throw new RuntimeException("Error loading recents component: " + clsName, t);
+            }
+            try {
+                impl = (RecentsImplementation) cls.newInstance();
+            } catch (Throwable t) {
+                throw new RuntimeException("Error creating recents component: " + clsName, t);
+            }
         }
-        try {
-            RecentsImplementation impl = (RecentsImplementation) cls.newInstance();
-            return impl;
-        } catch (Throwable t) {
-            throw new RuntimeException("Error creating recents component: " + clsName, t);
-        }
+
+        return impl;
     }
+
+    /** */
+    @Binds
+    @IntoMap
+    @ClassKey(OverviewProxyRecentsImpl.class)
+    public abstract RecentsImplementation bindOverviewProxyRecentsImpl(
+            OverviewProxyRecentsImpl impl);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 8670d1bd..264d644 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -17,8 +17,10 @@
 package com.android.systemui.screenshot;
 
 import static android.content.Context.NOTIFICATION_SERVICE;
+import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 
+import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_CORNER_FLOW;
 import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ACTION_INTENT;
 import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_CANCEL_NOTIFICATION;
 import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_DISALLOW_ENTER_PIP;
@@ -29,6 +31,7 @@
 import android.animation.AnimatorSet;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.Nullable;
 import android.app.ActivityOptions;
 import android.app.Notification;
 import android.app.Notification.BigPictureStyle;
@@ -59,12 +62,17 @@
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Environment;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.UserHandle;
+import android.provider.DeviceConfig;
 import android.provider.MediaStore;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
+import android.util.Log;
 import android.util.Slog;
 import android.view.Display;
 import android.view.LayoutInflater;
@@ -79,8 +87,8 @@
 
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.R;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.SystemUI;
+import com.android.systemui.dagger.qualifiers.MainResources;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.util.NotificationChannels;
@@ -96,7 +104,10 @@
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.function.Function;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
 
 
 /**
@@ -107,6 +118,7 @@
     Bitmap image;
     Uri imageUri;
     Runnable finisher;
+    Function<PendingIntent, Void> onEditReady;
     int iconSize;
     int previewWidth;
     int previewheight;
@@ -341,6 +353,9 @@
                     R.drawable.ic_screenshot_edit,
                     r.getString(com.android.internal.R.string.screenshot_edit), editAction);
             mNotificationBuilder.addAction(editActionBuilder.build());
+            if (editAction != null && mParams.onEditReady != null) {
+                mParams.onEditReady.apply(editAction);
+            }
 
             // Create a delete action for the notification
             PendingIntent deleteAction = PendingIntent.getBroadcast(context, requestCode,
@@ -378,40 +393,46 @@
             GlobalScreenshot.notifyScreenshotError(mParams.context, mNotificationManager,
                     mParams.errorMsgResId);
         } else {
-            // Show the final notification to indicate screenshot saved
-            Context context = mParams.context;
-            Resources r = context.getResources();
+            if (mParams.onEditReady != null) {
+                // Cancel the "saving screenshot" notification
+                mNotificationManager.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT);
+            } else {
+                // Show the final notification to indicate screenshot saved
+                Context context = mParams.context;
+                Resources r = context.getResources();
 
-            // Create the intent to show the screenshot in gallery
-            Intent launchIntent = new Intent(Intent.ACTION_VIEW);
-            launchIntent.setDataAndType(mParams.imageUri, "image/png");
-            launchIntent.setFlags(
-                    Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION);
+                // Create the intent to show the screenshot in gallery
+                Intent launchIntent = new Intent(Intent.ACTION_VIEW);
+                launchIntent.setDataAndType(mParams.imageUri, "image/png");
+                launchIntent.setFlags(
+                        Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION);
 
-            final long now = System.currentTimeMillis();
+                final long now = System.currentTimeMillis();
 
-            // Update the text and the icon for the existing notification
-            mPublicNotificationBuilder
+                // Update the text and the icon for the existing notification
+                mPublicNotificationBuilder
+                        .setContentTitle(r.getString(R.string.screenshot_saved_title))
+                        .setContentText(r.getString(R.string.screenshot_saved_text))
+                        .setContentIntent(
+                                PendingIntent.getActivity(mParams.context, 0, launchIntent, 0))
+                        .setWhen(now)
+                        .setAutoCancel(true)
+                        .setColor(context.getColor(
+                                com.android.internal.R.color.system_notification_accent_color));
+                mNotificationBuilder
                     .setContentTitle(r.getString(R.string.screenshot_saved_title))
                     .setContentText(r.getString(R.string.screenshot_saved_text))
                     .setContentIntent(PendingIntent.getActivity(mParams.context, 0, launchIntent, 0))
                     .setWhen(now)
                     .setAutoCancel(true)
                     .setColor(context.getColor(
-                            com.android.internal.R.color.system_notification_accent_color));
-            mNotificationBuilder
-                .setContentTitle(r.getString(R.string.screenshot_saved_title))
-                .setContentText(r.getString(R.string.screenshot_saved_text))
-                .setContentIntent(PendingIntent.getActivity(mParams.context, 0, launchIntent, 0))
-                .setWhen(now)
-                .setAutoCancel(true)
-                .setColor(context.getColor(
-                        com.android.internal.R.color.system_notification_accent_color))
-                .setPublicVersion(mPublicNotificationBuilder.build())
-                .setFlag(Notification.FLAG_NO_CLEAR, false);
+                            com.android.internal.R.color.system_notification_accent_color))
+                    .setPublicVersion(mPublicNotificationBuilder.build())
+                    .setFlag(Notification.FLAG_NO_CLEAR, false);
 
-            mNotificationManager.notify(SystemMessage.NOTE_GLOBAL_SCREENSHOT,
-                    mNotificationBuilder.build());
+                mNotificationManager.notify(SystemMessage.NOTE_GLOBAL_SCREENSHOT,
+                        mNotificationBuilder.build());
+            }
         }
         mParams.finisher.run();
         mParams.clearContext();
@@ -452,7 +473,8 @@
     }
 }
 
-class GlobalScreenshot {
+@Singleton
+public class GlobalScreenshot {
     static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id";
     static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent";
     static final String EXTRA_CANCEL_NOTIFICATION = "android:screenshot_cancel_notification";
@@ -470,8 +492,12 @@
     private static final float SCREENSHOT_SCALE = 1f;
     private static final float SCREENSHOT_DROP_IN_MIN_SCALE = SCREENSHOT_SCALE * 0.725f;
     private static final float SCREENSHOT_DROP_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.45f;
+    private static final float SCREENSHOT_CORNER_MIN_SCALE = SCREENSHOT_SCALE * 0.2f;
     private static final float SCREENSHOT_FAST_DROP_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.6f;
     private static final float SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET = 0f;
+    private static final float SCREENSHOT_CORNER_MIN_SCALE_OFFSET = .1f;
+    private static final long SCREENSHOT_CORNER_TIMEOUT_MILLIS = 8000;
+    private static final int MESSAGE_CORNER_TIMEOUT = 2;
     private final int mPreviewWidth;
     private final int mPreviewHeight;
 
@@ -499,23 +525,34 @@
 
     private MediaActionSound mCameraSound;
 
+    private final Handler mScreenshotHandler = new Handler(Looper.getMainLooper()) {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MESSAGE_CORNER_TIMEOUT:
+                    GlobalScreenshot.this.clearScreenshot();
+                    break;
+                default:
+                    break;
+            }
+        }
+    };
+
 
     /**
      * @param context everything needs a context :(
      */
-    public GlobalScreenshot(Context context) {
-        Resources r = context.getResources();
+    @Inject
+    public GlobalScreenshot(Context context, @MainResources Resources resources,
+            LayoutInflater layoutInflater) {
         mContext = context;
-        LayoutInflater layoutInflater = (LayoutInflater)
-                context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 
         // Inflate the screenshot layout
         mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot, null);
-        mBackgroundView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_background);
-        mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot);
-        mScreenshotFlash = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_flash);
-        mScreenshotSelectorView = (ScreenshotSelectorView) mScreenshotLayout.findViewById(
-                R.id.global_screenshot_selector);
+        mBackgroundView = mScreenshotLayout.findViewById(R.id.global_screenshot_background);
+        mScreenshotView = mScreenshotLayout.findViewById(R.id.global_screenshot);
+        mScreenshotFlash = mScreenshotLayout.findViewById(R.id.global_screenshot_flash);
+        mScreenshotSelectorView = mScreenshotLayout.findViewById(R.id.global_screenshot_selector);
         mScreenshotLayout.setFocusable(true);
         mScreenshotSelectorView.setFocusable(true);
         mScreenshotSelectorView.setFocusableInTouchMode(true);
@@ -546,16 +583,16 @@
 
         // Get the various target sizes
         mNotificationIconSize =
-            r.getDimensionPixelSize(android.R.dimen.notification_large_icon_height);
+            resources.getDimensionPixelSize(android.R.dimen.notification_large_icon_height);
 
         // Scale has to account for both sides of the bg
-        mBgPadding = (float) r.getDimensionPixelSize(R.dimen.global_screenshot_bg_padding);
+        mBgPadding = (float) resources.getDimensionPixelSize(R.dimen.global_screenshot_bg_padding);
         mBgPaddingScale = mBgPadding /  mDisplayMetrics.widthPixels;
 
         // determine the optimal preview size
         int panelWidth = 0;
         try {
-            panelWidth = r.getDimensionPixelSize(R.dimen.notification_panel_width);
+            panelWidth = resources.getDimensionPixelSize(R.dimen.notification_panel_width);
         } catch (Resources.NotFoundException e) {
         }
         if (panelWidth <= 0) {
@@ -563,7 +600,7 @@
             panelWidth = mDisplayMetrics.widthPixels;
         }
         mPreviewWidth = panelWidth;
-        mPreviewHeight = r.getDimensionPixelSize(R.dimen.notification_max_height);
+        mPreviewHeight = resources.getDimensionPixelSize(R.dimen.notification_max_height);
 
         // Setup the Camera shutter sound
         mCameraSound = new MediaActionSound();
@@ -573,12 +610,14 @@
     /**
      * Creates a new worker thread and saves the screenshot to the media store.
      */
-    private void saveScreenshotInWorkerThread(Runnable finisher) {
+    private void saveScreenshotInWorkerThread(
+            Runnable finisher, @Nullable Function<PendingIntent, Void> onEditReady) {
         SaveImageInBackgroundData data = new SaveImageInBackgroundData();
         data.context = mContext;
         data.image = mScreenBitmap;
         data.iconSize = mNotificationIconSize;
         data.finisher = finisher;
+        data.onEditReady = onEditReady;
         data.previewWidth = mPreviewWidth;
         data.previewheight = mPreviewHeight;
         if (mSaveInBgTask != null) {
@@ -588,6 +627,10 @@
                 .execute();
     }
 
+    private void saveScreenshotInWorkerThread(Runnable finisher) {
+        saveScreenshotInWorkerThread(finisher, null);
+    }
+
     /**
      * Takes a screenshot of the current display and shows an animation.
      */
@@ -682,6 +725,22 @@
     }
 
     /**
+     * Clears current screenshot
+     */
+    private void clearScreenshot() {
+        if (mScreenshotLayout.isAttachedToWindow()) {
+            mWindowManager.removeView(mScreenshotLayout);
+        }
+
+        // Clear any references to the bitmap
+        mScreenBitmap = null;
+        mScreenshotView.setImageBitmap(null);
+        mBackgroundView.setVisibility(View.GONE);
+        mScreenshotView.setVisibility(View.GONE);
+        mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null);
+    }
+
+    /**
      * Starts the animation after taking the screenshot
      */
     private void startAnimation(final Runnable finisher, int w, int h, boolean statusBarVisible,
@@ -705,34 +764,55 @@
             mScreenshotAnimation.removeAllListeners();
         }
 
+        boolean useCornerFlow =
+                DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, SCREENSHOT_CORNER_FLOW, false);
         mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
         ValueAnimator screenshotDropInAnim = createScreenshotDropInAnimation();
-        ValueAnimator screenshotFadeOutAnim = createScreenshotDropOutAnimation(w, h,
-                statusBarVisible, navBarVisible);
+        ValueAnimator screenshotFadeOutAnim = useCornerFlow
+                ? createScreenshotToCornerAnimation(w, h)
+                : createScreenshotDropOutAnimation(w, h, statusBarVisible, navBarVisible);
         mScreenshotAnimation = new AnimatorSet();
         mScreenshotAnimation.playSequentially(screenshotDropInAnim, screenshotFadeOutAnim);
         mScreenshotAnimation.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
                 // Save the screenshot once we have a bit of time now
-                saveScreenshotInWorkerThread(finisher);
-                mWindowManager.removeView(mScreenshotLayout);
-
-                // Clear any references to the bitmap
-                mScreenBitmap = null;
-                mScreenshotView.setImageBitmap(null);
+                if (!useCornerFlow) {
+                    saveScreenshotInWorkerThread(finisher);
+                    clearScreenshot();
+                } else {
+                    mScreenshotView.requestFocus();
+                    mScreenshotView.setOnClickListener((v) -> {
+                        // TODO: remove once we have a better UI to show that we aren't ready yet
+                        Toast notReadyToast = Toast.makeText(
+                                mContext, "Screenshot is not ready yet", Toast.LENGTH_SHORT);
+                        notReadyToast.show();
+                    });
+                    saveScreenshotInWorkerThread(finisher, intent -> {
+                        mScreenshotHandler.post(() -> mScreenshotView.setOnClickListener(v -> {
+                            try {
+                                intent.send();
+                                clearScreenshot();
+                            } catch (PendingIntent.CanceledException e) {
+                                Log.e(TAG, "Edit intent cancelled", e);
+                            }
+                            mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
+                        }));
+                        return null;
+                    });
+                    mScreenshotHandler.sendMessageDelayed(
+                            mScreenshotHandler.obtainMessage(MESSAGE_CORNER_TIMEOUT),
+                            SCREENSHOT_CORNER_TIMEOUT_MILLIS);
+                }
             }
         });
-        mScreenshotLayout.post(new Runnable() {
-            @Override
-            public void run() {
-                // Play the shutter sound to notify that we've taken a screenshot
-                mCameraSound.play(MediaActionSound.SHUTTER_CLICK);
+        mScreenshotHandler.post(() -> {
+            // Play the shutter sound to notify that we've taken a screenshot
+            mCameraSound.play(MediaActionSound.SHUTTER_CLICK);
 
-                mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-                mScreenshotView.buildLayer();
-                mScreenshotAnimation.start();
-            }
+            mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+            mScreenshotView.buildLayer();
+            mScreenshotAnimation.start();
         });
     }
     private ValueAnimator createScreenshotDropInAnimation() {
@@ -877,6 +957,47 @@
         return anim;
     }
 
+    private ValueAnimator createScreenshotToCornerAnimation(int w, int h) {
+        ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
+        anim.setStartDelay(SCREENSHOT_DROP_OUT_DELAY);
+
+        final float scaleDurationPct =
+                (float) SCREENSHOT_DROP_OUT_SCALE_DURATION / SCREENSHOT_DROP_OUT_DURATION;
+        final Interpolator scaleInterpolator = new Interpolator() {
+            @Override
+            public float getInterpolation(float x) {
+                if (x < scaleDurationPct) {
+                    // Decelerate, and scale the input accordingly
+                    return (float) (1f - Math.pow(1f - (x / scaleDurationPct), 2f));
+                }
+                return 1f;
+            }
+        };
+
+        // Determine the bounds of how to scale
+        float halfScreenWidth = (w - 2f * mBgPadding) / 2f;
+        float halfScreenHeight = (h - 2f * mBgPadding) / 2f;
+        final float offsetPct = SCREENSHOT_CORNER_MIN_SCALE_OFFSET;
+        final PointF finalPos = new PointF(
+                -halfScreenWidth + (SCREENSHOT_CORNER_MIN_SCALE + offsetPct) * halfScreenWidth,
+                halfScreenHeight - (SCREENSHOT_CORNER_MIN_SCALE + offsetPct) * halfScreenHeight);
+
+        // Animate the screenshot to the bottom left corner
+        anim.setDuration(SCREENSHOT_DROP_OUT_DURATION);
+        anim.addUpdateListener(animation -> {
+            float t = (Float) animation.getAnimatedValue();
+            float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)
+                    - scaleInterpolator.getInterpolation(t)
+                    * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_CORNER_MIN_SCALE);
+            mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);
+            mScreenshotView.setScaleX(scaleT);
+            mScreenshotView.setScaleY(scaleT);
+            mScreenshotView.setTranslationX(t * finalPos.x);
+            mScreenshotView.setTranslationY(t * finalPos.y);
+        });
+        return anim;
+    }
+
     static void notifyScreenshotError(Context context, NotificationManager nManager, int msgResId) {
         Resources r = context.getResources();
         String errorMsg = r.getString(msgResId);
@@ -917,6 +1038,12 @@
      */
     public static class ActionProxyReceiver extends BroadcastReceiver {
         static final int CLOSE_WINDOWS_TIMEOUT_MILLIS = 3000;
+        private final StatusBar mStatusBar;
+
+        @Inject
+        public ActionProxyReceiver(StatusBar statusBar) {
+            mStatusBar = statusBar;
+        }
 
         @Override
         public void onReceive(Context context, final Intent intent) {
@@ -939,8 +1066,8 @@
                         intent.getBooleanExtra(EXTRA_DISALLOW_ENTER_PIP, false));
                 context.startActivityAsUser(actionIntent, opts.toBundle(), UserHandle.CURRENT);
             };
-            StatusBar statusBar = SysUiServiceProvider.getComponent(context, StatusBar.class);
-            statusBar.executeRunnableDismissingKeyguard(startActivityRunnable, null,
+
+            mStatusBar.executeRunnableDismissingKeyguard(startActivityRunnable, null,
                     true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 34b8bfe..20d24e6 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -27,10 +27,15 @@
 import android.util.Log;
 import android.view.WindowManager;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+@Singleton
 public class TakeScreenshotService extends Service {
     private static final String TAG = "TakeScreenshotService";
 
-    private static GlobalScreenshot mScreenshot;
+    private final GlobalScreenshot mScreenshot;
+    private final UserManager mUserManager;
 
     private Handler mHandler = new Handler() {
         @Override
@@ -50,16 +55,12 @@
             // If the storage for this user is locked, we have no place to store
             // the screenshot, so skip taking it instead of showing a misleading
             // animation and error notification.
-            if (!getSystemService(UserManager.class).isUserUnlocked()) {
+            if (!mUserManager.isUserUnlocked()) {
                 Log.w(TAG, "Skipping screenshot because storage is locked!");
                 post(finisher);
                 return;
             }
 
-            if (mScreenshot == null) {
-                mScreenshot = new GlobalScreenshot(TakeScreenshotService.this);
-            }
-
             switch (msg.what) {
                 case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
                     mScreenshot.takeScreenshot(finisher, msg.arg1 > 0, msg.arg2 > 0);
@@ -73,6 +74,12 @@
         }
     };
 
+    @Inject
+    public TakeScreenshotService(GlobalScreenshot globalScreenshot, UserManager userManager) {
+        mScreenshot = globalScreenshot;
+        mUserManager = userManager;
+    }
+
     @Override
     public IBinder onBind(Intent intent) {
         return new Messenger(mHandler).getBinder();
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index 176676f..b1f1f38 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -44,6 +44,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.RestrictedLockUtilsInternal;
 import com.android.systemui.Dependency;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 
 import java.util.ArrayList;
 
@@ -281,12 +282,13 @@
         }
     };
 
-    public BrightnessController(Context context, ToggleSlider control) {
+    public BrightnessController(Context context, ToggleSlider control,
+            BroadcastDispatcher broadcastDispatcher) {
         mContext = context;
         mControl = control;
         mControl.setMax(GAMMA_SPACE_MAX);
         mBackgroundHandler = new Handler((Looper) Dependency.get(Dependency.BG_LOOPER));
-        mUserTracker = new CurrentUserTracker(mContext) {
+        mUserTracker = new CurrentUserTracker(broadcastDispatcher) {
             @Override
             public void onUserSwitched(int newUserId) {
                 mBackgroundHandler.post(mUpdateModeRunnable);
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
index d8b4df5..70c2531 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
@@ -28,11 +28,21 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+
+import javax.inject.Inject;
 
 /** A dialog that provides controls for adjusting the screen brightness. */
 public class BrightnessDialog extends Activity {
 
     private BrightnessController mBrightnessController;
+    private final BroadcastDispatcher mBroadcastDispatcher;
+
+    @Inject
+    public BrightnessDialog(BroadcastDispatcher broadcastDispatcher) {
+        mBroadcastDispatcher = broadcastDispatcher;
+    }
+
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -49,7 +59,7 @@
         setContentView(v);
 
         final ToggleSliderView slider = findViewById(R.id.brightness_slider);
-        mBrightnessController = new BrightnessController(this, slider);
+        mBrightnessController = new BrightnessController(this, slider, mBroadcastDispatcher);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserObservable.java b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserObservable.java
index 3cf08b4..3cdc01d 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserObservable.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserObservable.java
@@ -16,11 +16,11 @@
 
 package com.android.systemui.settings;
 
-import android.content.Context;
-
 import androidx.lifecycle.LiveData;
 import androidx.lifecycle.MutableLiveData;
 
+import com.android.systemui.broadcast.BroadcastDispatcher;
+
 /**
  * A class that has an observable for the current user.
  */
@@ -42,8 +42,8 @@
         }
     };
 
-    public CurrentUserObservable(Context context) {
-        mTracker = new CurrentUserTracker(context) {
+    public CurrentUserObservable(BroadcastDispatcher broadcastDispatcher) {
+        mTracker = new CurrentUserTracker(broadcastDispatcher) {
             @Override
             public void onUserSwitched(int newUserId) {
                 mCurrentUser.setValue(newUserId);
diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
index 0b89dc1..9f79785 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserTracker.java
@@ -23,6 +23,7 @@
 import android.content.IntentFilter;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -33,8 +34,8 @@
 
     private Consumer<Integer> mCallback = this::onUserSwitched;
 
-    public CurrentUserTracker(Context context) {
-        this(UserReceiver.getInstance(context));
+    public CurrentUserTracker(BroadcastDispatcher broadcastDispatcher) {
+        this(UserReceiver.getInstance(broadcastDispatcher));
     }
 
     @VisibleForTesting
@@ -60,20 +61,20 @@
     static class UserReceiver extends BroadcastReceiver {
         private static UserReceiver sInstance;
 
-        private Context mAppContext;
         private boolean mReceiverRegistered;
         private int mCurrentUserId;
+        private final BroadcastDispatcher mBroadcastDispatcher;
 
         private List<Consumer<Integer>> mCallbacks = new ArrayList<>();
 
         @VisibleForTesting
-        UserReceiver(Context context) {
-            mAppContext = context.getApplicationContext();
+        UserReceiver(BroadcastDispatcher broadcastDispatcher) {
+            mBroadcastDispatcher = broadcastDispatcher;
         }
 
-        static UserReceiver getInstance(Context context) {
+        static UserReceiver getInstance(BroadcastDispatcher broadcastDispatcher) {
             if (sInstance == null) {
-                sInstance = new UserReceiver(context);
+                sInstance = new UserReceiver(broadcastDispatcher);
             }
             return sInstance;
         }
@@ -96,7 +97,7 @@
             if (!mReceiverRegistered) {
                 mCurrentUserId = ActivityManager.getCurrentUser();
                 IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
-                mAppContext.registerReceiver(this, filter);
+                mBroadcastDispatcher.registerReceiver(this, filter);
                 mReceiverRegistered = true;
             }
         }
@@ -105,7 +106,7 @@
             if (mCallbacks.contains(callback)) {
                 mCallbacks.remove(callback);
                 if (mCallbacks.size() == 0 && mReceiverRegistered) {
-                    mAppContext.unregisterReceiver(this);
+                    mBroadcastDispatcher.unregisterReceiver(this);
                     mReceiverRegistered = false;
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 34f5437..eb6ea13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -56,12 +56,14 @@
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.view.AppearanceRegion;
-import com.android.systemui.SystemUI;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
 import com.android.systemui.statusbar.policy.CallbackController;
 
 import java.util.ArrayList;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
 /**
  * This class takes the functions from IStatusBar that come in on
  * binder pool threads and posts messages to get them onto the main
@@ -69,6 +71,7 @@
  * coalescing these calls so they don't stack up.  For the calls
  * are coalesced, note that they are all idempotent.
  */
+@Singleton
 public class CommandQueue extends IStatusBar.Stub implements CallbackController<Callbacks>,
         DisplayManager.DisplayListener {
     private static final int INDEX_MASK = 0xffff;
@@ -305,6 +308,7 @@
     }
 
     @VisibleForTesting
+    @Inject
     public CommandQueue(Context context) {
         context.getSystemService(DisplayManager.class).registerDisplayListener(this, mHandler);
         // We always have default display.
@@ -1186,17 +1190,4 @@
             }
         }
     }
-
-    // Need this class since CommandQueue already extends IStatusBar.Stub, so CommandQueueStart
-    // is needed so it can extend SystemUI.
-    public static class CommandQueueStart extends SystemUI {
-        public CommandQueueStart(Context context) {
-            super(context);
-        }
-
-        @Override
-        public void start() {
-            putComponent(CommandQueue.class, new CommandQueue(mContext));
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
index 1f38904..9f5cf68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -18,8 +18,6 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
-import static com.android.systemui.SysUiServiceProvider.getComponent;
-
 import android.content.Context;
 import android.hardware.display.DisplayManager;
 import android.os.Handler;
@@ -66,14 +64,12 @@
     SparseArray<NavigationBarFragment> mNavigationBars = new SparseArray<>();
 
     @Inject
-    public NavigationBarController(Context context, @MainHandler Handler handler) {
+    public NavigationBarController(Context context, @MainHandler Handler handler,
+            CommandQueue commandQueue) {
         mContext = context;
         mHandler = handler;
         mDisplayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
-        CommandQueue commandQueue = getComponent(mContext, CommandQueue.class);
-        if (commandQueue != null) {
-            commandQueue.addCallback(this);
-        }
+        commandQueue.addCallback(this);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 7adf7af..571d3d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -46,6 +46,7 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.recents.OverviewProxyService;
@@ -90,6 +91,7 @@
     private final UserManager mUserManager;
     private final IStatusBarService mBarService;
     private final List<UserChangedListener> mListeners = new ArrayList<>();
+    private final BroadcastDispatcher mBroadcastDispatcher;
 
     private boolean mShowLockscreenNotifications;
     private boolean mAllowLockscreenRemoteInput;
@@ -180,7 +182,8 @@
     }
 
     @Inject
-    public NotificationLockscreenUserManagerImpl(Context context) {
+    public NotificationLockscreenUserManagerImpl(Context context,
+            BroadcastDispatcher broadcastDispatcher) {
         mContext = context;
         mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
                 Context.DEVICE_POLICY_SERVICE);
@@ -191,6 +194,7 @@
         Dependency.get(StatusBarStateController.class).addCallback(this);
         mLockPatternUtils = new LockPatternUtils(context);
         mKeyguardManager = context.getSystemService(KeyguardManager.class);
+        mBroadcastDispatcher = broadcastDispatcher;
     }
 
     public void setUpWithPresenter(NotificationPresenter presenter) {
@@ -244,15 +248,15 @@
                     UserHandle.USER_ALL);
         }
 
-        mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL,
+        mBroadcastDispatcher.registerReceiver(mAllUsersReceiver,
                 new IntentFilter(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
-                null, null);
+                null /* handler */, UserHandle.ALL);
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(Intent.ACTION_USER_ADDED);
         filter.addAction(Intent.ACTION_USER_UNLOCKED);
-        mContext.registerReceiver(mBaseBroadcastReceiver, filter);
+        mBroadcastDispatcher.registerReceiver(mBaseBroadcastReceiver, filter);
 
         IntentFilter internalFilter = new IntentFilter();
         internalFilter.addAction(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 0988e34..d668665 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -163,7 +163,7 @@
                 if (!isPlaybackActive(state.getState())) {
                     clearCurrentMediaNotification();
                 }
-                dispatchUpdateMediaMetaData(true /* changed */, true /* allowAnimation */);
+                findAndUpdateMediaNotifications();
             }
         }
 
@@ -200,6 +200,16 @@
         mEntryManager = notificationEntryManager;
         notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
+            public void onPendingEntryAdded(NotificationEntry entry) {
+                findAndUpdateMediaNotifications();
+            }
+
+            @Override
+            public void onPreEntryUpdated(NotificationEntry entry) {
+                findAndUpdateMediaNotifications();
+            }
+
+            @Override
             public void onEntryRemoved(
                     NotificationEntry entry,
                     NotificationVisibility visibility,
@@ -272,16 +282,12 @@
         boolean metaDataChanged = false;
 
         synchronized (mEntryManager.getNotificationData()) {
-            ArrayList<NotificationEntry> activeNotifications =
-                    mEntryManager.getNotificationData().getActiveNotifications();
-            final int N = activeNotifications.size();
+            Set<NotificationEntry> allNotifications = mEntryManager.getAllNotifs();
 
             // Promote the media notification with a controller in 'playing' state, if any.
             NotificationEntry mediaNotification = null;
             MediaController controller = null;
-            for (int i = 0; i < N; i++) {
-                final NotificationEntry entry = activeNotifications.get(i);
-
+            for (NotificationEntry entry : allNotifications) {
                 if (entry.isMediaNotification()) {
                     final MediaSession.Token token =
                             entry.getSbn().getNotification().extras.getParcelable(
@@ -319,8 +325,7 @@
                             // now to see if we have one like this
                             final String pkg = aController.getPackageName();
 
-                            for (int i = 0; i < N; i++) {
-                                final NotificationEntry entry = activeNotifications.get(i);
+                            for (NotificationEntry entry : allNotifications) {
                                 if (entry.getSbn().getPackageName().equals(pkg)) {
                                     if (DEBUG_MEDIA) {
                                         Log.v(TAG, "DEBUG_MEDIA: found controller matching "
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index c838ac5..35f06f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -59,6 +59,7 @@
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.policy.RemoteInputUriController;
 import com.android.systemui.statusbar.policy.RemoteInputView;
 
 import java.io.FileDescriptor;
@@ -121,6 +122,7 @@
     private final UserManager mUserManager;
     private final KeyguardManager mKeyguardManager;
     private final StatusBarStateController mStatusBarStateController;
+    private final RemoteInputUriController mRemoteInputUriController;
 
     protected RemoteInputController mRemoteInputController;
     protected NotificationLifetimeExtender.NotificationSafeToRemoveCallback
@@ -260,7 +262,8 @@
             NotificationEntryManager notificationEntryManager,
             Lazy<ShadeController> shadeController,
             StatusBarStateController statusBarStateController,
-            @MainHandler Handler mainHandler) {
+            @MainHandler Handler mainHandler,
+            RemoteInputUriController remoteInputUriController) {
         mContext = context;
         mLockscreenUserManager = lockscreenUserManager;
         mSmartReplyController = smartReplyController;
@@ -273,6 +276,7 @@
         addLifetimeExtenders();
         mKeyguardManager = context.getSystemService(KeyguardManager.class);
         mStatusBarStateController = statusBarStateController;
+        mRemoteInputUriController = remoteInputUriController;
 
         notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
@@ -300,7 +304,7 @@
     /** Initializes this component with the provided dependencies. */
     public void setUpWithCallback(Callback callback, RemoteInputController.Delegate delegate) {
         mCallback = callback;
-        mRemoteInputController = new RemoteInputController(delegate);
+        mRemoteInputController = new RemoteInputController(delegate, mRemoteInputUriController);
         mRemoteInputController.addCallback(new RemoteInputController.Callback() {
             @Override
             public void onRemoteInputSent(NotificationEntry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index d6b87af..20a3e35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -21,7 +21,6 @@
 import android.os.Handler;
 import android.os.Trace;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
@@ -40,6 +39,7 @@
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.util.Assert;
+import com.android.systemui.util.Utils;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -146,9 +146,7 @@
         final int N = activeNotifications.size();
         for (int i = 0; i < N; i++) {
             NotificationEntry ent = activeNotifications.get(i);
-            int flag = Settings.System.getInt(mContext.getContentResolver(),
-                    "qs_media_player", 0);
-            boolean hideMedia = (flag == 1);
+            boolean hideMedia = Utils.useQsMediaPlayer(mContext);
             if (ent.isRowDismissed() || ent.isRowRemoved()
                     || (ent.isMediaNotification() && hideMedia)
                     || mBubbleController.isBubbleNotificationSuppressedFromShade(ent.getKey())) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index 998cf52..778443c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -19,12 +19,15 @@
 import android.app.Notification;
 import android.app.RemoteInput;
 import android.content.Context;
+import android.net.Uri;
 import android.os.SystemProperties;
+import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
 import android.util.Pair;
 
 import com.android.internal.util.Preconditions;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.policy.RemoteInputUriController;
 import com.android.systemui.statusbar.policy.RemoteInputView;
 
 import java.lang.ref.WeakReference;
@@ -43,9 +46,12 @@
     private final ArrayMap<String, Object> mSpinning = new ArrayMap<>();
     private final ArrayList<Callback> mCallbacks = new ArrayList<>(3);
     private final Delegate mDelegate;
+    private final RemoteInputUriController mRemoteInputUriController;
 
-    public RemoteInputController(Delegate delegate) {
+    public RemoteInputController(Delegate delegate,
+            RemoteInputUriController remoteInputUriController) {
         mDelegate = delegate;
+        mRemoteInputUriController = remoteInputUriController;
     }
 
     /**
@@ -272,6 +278,14 @@
         mDelegate.lockScrollTo(entry);
     }
 
+    /**
+     * Create a temporary grant which allows the app that submitted the notification access to the
+     * specified URI.
+     */
+    public void grantInlineReplyUriPermission(StatusBarNotification sbn, Uri data) {
+        mRemoteInputUriController.grantInlineReplyUriPermission(sbn, data);
+    }
+
     public interface Callback {
         default void onRemoteInputActive(boolean active) {}
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index f284f73..49bed15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.notification;
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
@@ -52,7 +53,6 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.DockedStackExistsListener;
 import com.android.systemui.R;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.SystemUI;
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.statusbar.CommandQueue;
@@ -61,9 +61,13 @@
 
 import java.util.List;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
 /** The class to show notification(s) of instant apps. This may show multiple notifications on
  * splitted screen.
  */
+@Singleton
 public class InstantAppNotifier extends SystemUI
         implements CommandQueue.Callbacks, KeyguardStateController.Callback {
     private static final String TAG = "InstantAppNotifier";
@@ -72,11 +76,14 @@
     private final Handler mHandler = new Handler();
     private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
     private final ArraySet<Pair<String, Integer>> mCurrentNotifs = new ArraySet<>();
+    private final CommandQueue mCommandQueue;
     private boolean mDockedStackExists;
     private KeyguardStateController mKeyguardStateController;
 
-    public InstantAppNotifier(Context context) {
+    @Inject
+    public InstantAppNotifier(Context context, CommandQueue commandQueue) {
         super(context);
+        mCommandQueue = commandQueue;
     }
 
     @Override
@@ -90,7 +97,7 @@
             // Ignore
         }
 
-        SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallback(this);
+        mCommandQueue.addCallback(this);
         mKeyguardStateController.addCallback(this);
 
         DockedStackExistsListener.register(
@@ -155,7 +162,8 @@
                                     focusedStack.configuration.windowConfiguration
                                             .getWindowingMode();
                             if (windowingMode == WINDOWING_MODE_FULLSCREEN
-                                    || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
+                                    || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+                                    || windowingMode == WINDOWING_MODE_FREEFORM) {
                                 checkAndPostForStack(focusedStack, notifs, noMan, pm);
                             }
                         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
index dfc6450..df78fa3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
@@ -20,12 +20,12 @@
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
 
+import androidx.annotation.NonNull;
+
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
 
-import androidx.annotation.NonNull;
-
 /**
  * Listener interface for changes sent by NotificationEntryManager.
  */
@@ -37,13 +37,6 @@
     default void onPendingEntryAdded(NotificationEntry entry) {
     }
 
-    // TODO: Combine this with onPreEntryUpdated into "onBeforeEntryFiltered" or similar
-    /**
-     * Called when a new entry is created but before it has been filtered or displayed to the user.
-     */
-    default void onBeforeNotificationAdded(NotificationEntry entry) {
-    }
-
     /**
      * Called when a new entry is created.
      */
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 6e464f4..404087d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -53,8 +53,10 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -138,6 +140,14 @@
         mNotificationEntryListeners.add(listener);
     }
 
+    /**
+     * Removes a {@link NotificationEntryListener} previously registered via
+     * {@link #addNotificationEntryListener(NotificationEntryListener)}.
+     */
+    public void removeNotificationEntryListener(NotificationEntryListener listener) {
+        mNotificationEntryListeners.remove(listener);
+    }
+
     /** Sets the {@link NotificationRemoveInterceptor}. */
     public void setNotificationRemoveInterceptor(NotificationRemoveInterceptor interceptor) {
         mRemoveInterceptor = interceptor;
@@ -254,9 +264,6 @@
                     listener.onEntryInflated(entry, inflatedFlags);
                 }
                 mNotificationData.add(entry);
-                for (NotificationEntryListener listener : mNotificationEntryListeners) {
-                    listener.onBeforeNotificationAdded(entry);
-                }
                 updateNotifications("onAsyncInflationFinished");
                 for (NotificationEntryListener listener : mNotificationEntryListeners) {
                     listener.onNotificationAdded(entry);
@@ -555,6 +562,27 @@
         return mPendingNotifications.values();
     }
 
+    /**
+     * @return all notification we're currently aware of (both pending and visible notifications)
+     */
+    public Set<NotificationEntry> getAllNotifs() {
+        Set<NotificationEntry> allNotifs = new HashSet<>(mPendingNotifications.values());
+        allNotifs.addAll(mNotificationData.getActiveNotifications());
+        return allNotifs;
+    }
+
+    /**
+     * Gets the pending or visible notification entry with the given key. Returns null if
+     * notification doesn't exist.
+     */
+    public NotificationEntry getPendingOrCurrentNotif(String key) {
+        if (mPendingNotifications.containsKey(key)) {
+            return mPendingNotifications.get(key);
+        } else {
+            return mNotificationData.get(key);
+        }
+    }
+
     private void extendLifetime(NotificationEntry entry, NotificationLifetimeExtender extender) {
         NotificationLifetimeExtender activeExtender = mRetainedNotifications.get(entry);
         if (activeExtender != null && activeExtender != extender) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
index 533dfb6..2eefe29 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
@@ -18,10 +18,6 @@
 
 import static com.android.internal.util.Preconditions.checkNotNull;
 
-import android.os.UserHandle;
-import android.service.notification.StatusBarNotification;
-import android.util.ArraySet;
-
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.ForegroundServiceController;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -70,11 +66,6 @@
                 boolean removedByUser) {
             mListContainer.cleanUpViewStateForEntry(entry);
         }
-
-        @Override
-        public void onBeforeNotificationAdded(NotificationEntry entry) {
-            tagForeground(entry.getSbn());
-        }
     };
 
     private final DeviceProvisionedListener mDeviceProvisionedListener =
@@ -84,29 +75,4 @@
                     mEntryManager.updateNotifications("device provisioned changed");
                 }
             };
-
-    // TODO: This method is horrifically inefficient
-    private void tagForeground(StatusBarNotification notification) {
-        ArraySet<Integer> activeOps =
-                mForegroundServiceController.getAppOps(
-                        notification.getUserId(), notification.getPackageName());
-        if (activeOps != null) {
-            int len = activeOps.size();
-            for (int i = 0; i < len; i++) {
-                updateNotificationsForAppOp(activeOps.valueAt(i), notification.getUid(),
-                        notification.getPackageName(), true);
-            }
-        }
-    }
-
-    /** When an app op changes, propagate that change to notifications. */
-    public void updateNotificationsForAppOp(int appOp, int uid, String pkg, boolean showIcon) {
-        String foregroundKey =
-                mForegroundServiceController.getStandardLayoutKey(UserHandle.getUserId(uid), pkg);
-        if (foregroundKey != null) {
-            mEntryManager
-                    .getNotificationData().updateAppOp(appOp, uid, pkg, foregroundKey, showIcon);
-            mEntryManager.updateNotifications("app opp changed pkg=" + pkg);
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
index 7e398bb..a0229d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
@@ -37,6 +37,7 @@
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
 import com.android.systemui.statusbar.notification.logging.NotifEvent;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
@@ -67,7 +68,6 @@
 
     private final ArrayMap<String, NotificationEntry> mEntries = new ArrayMap<>();
     private final ArrayList<NotificationEntry> mSortedAndFiltered = new ArrayList<>();
-    private final ArrayList<NotificationEntry> mFilteredForUser = new ArrayList<>();
 
     private final NotificationGroupManager mGroupManager =
             Dependency.get(NotificationGroupManager.class);
@@ -76,12 +76,16 @@
     private final Ranking mTmpRanking = new Ranking();
     private final boolean mUsePeopleFiltering;
     private final NotifLog mNotifLog;
+    private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
 
     @Inject
-    public NotificationData(NotificationSectionsFeatureManager sectionsFeatureManager,
-            NotifLog notifLog) {
+    public NotificationData(
+            NotificationSectionsFeatureManager sectionsFeatureManager,
+            NotifLog notifLog,
+            PeopleNotificationIdentifier peopleNotificationIdentifier) {
         mUsePeopleFiltering = sectionsFeatureManager.isFilteringEnabled();
         mNotifLog = notifLog;
+        mPeopleNotificationIdentifier = peopleNotificationIdentifier;
     }
 
     public void setHeadsUpManager(HeadsUpManager headsUpManager) {
@@ -161,20 +165,20 @@
     }
 
     public ArrayList<NotificationEntry> getNotificationsForCurrentUser() {
-        mFilteredForUser.clear();
-
         synchronized (mEntries) {
             final int len = mEntries.size();
+            ArrayList<NotificationEntry> filteredForUser = new ArrayList<>(len);
+
             for (int i = 0; i < len; i++) {
                 NotificationEntry entry = mEntries.valueAt(i);
                 final StatusBarNotification sbn = entry.getSbn();
                 if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) {
                     continue;
                 }
-                mFilteredForUser.add(entry);
+                filteredForUser.add(entry);
             }
+            return filteredForUser;
         }
-        return mFilteredForUser;
     }
 
     public NotificationEntry get(String key) {
@@ -220,24 +224,6 @@
         updateRankingAndSort(ranking, reason);
     }
 
-    public void updateAppOp(int appOp, int uid, String pkg, String key, boolean showIcon) {
-        synchronized (mEntries) {
-            final int len = mEntries.size();
-            for (int i = 0; i < len; i++) {
-                NotificationEntry entry = mEntries.valueAt(i);
-                if (uid == entry.getSbn().getUid()
-                        && pkg.equals(entry.getSbn().getPackageName())
-                        && key.equals(entry.getKey())) {
-                    if (showIcon) {
-                        entry.mActiveAppOps.add(appOp);
-                    } else {
-                        entry.mActiveAppOps.remove(appOp);
-                    }
-                }
-            }
-        }
-    }
-
     /**
      * Returns true if this notification should be displayed in the high-priority notifications
      * section
@@ -460,8 +446,7 @@
     }
 
     private boolean isPeopleNotification(NotificationEntry e) {
-        return e.getSbn().getNotification().getNotificationStyle()
-                == Notification.MessagingStyle.class;
+        return mPeopleNotificationIdentifier.isPeopleNotification(e.getSbn());
     }
 
     public void dump(PrintWriter pw, String indent) {
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 71fc549..a4c8fc4 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
@@ -130,7 +130,7 @@
     private Throwable mDebugThrowable;
     public CharSequence remoteInputTextWhenReset;
     public long lastRemoteInputSent = NOT_LAUNCHED_YET;
-    public ArraySet<Integer> mActiveAppOps = new ArraySet<>(3);
+    public final ArraySet<Integer> mActiveAppOps = new ArraySet<>(3);
     public CharSequence headsUpStatusBarText;
     public CharSequence headsUpStatusBarTextPublic;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
index 396c5fe..0ef75165 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
@@ -142,6 +142,7 @@
             entry.updateIcons(mContext, sbn);
             entry.reset();
             updateNotification(entry, pmUser, sbn, entry.getRow());
+            entry.getRow().setOnDismissRunnable(onDismissRunnable);
         } else {
             entry.createIcons(mContext, sbn);
             new RowInflaterTask().inflate(mContext, parent, entry,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt
index 8c067b7..4f03003 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt
@@ -23,15 +23,25 @@
 abstract class PeopleHubModule {
 
     @Binds
-    abstract fun peopleHubSectionFooterViewController(
-        viewAdapter: PeopleHubSectionFooterViewAdapterImpl
+    abstract fun peopleHubSectionFooterViewAdapter(
+        impl: PeopleHubSectionFooterViewAdapterImpl
     ): PeopleHubSectionFooterViewAdapter
 
     @Binds
-    abstract fun peopleHubDataSource(s: PeopleHubDataSourceImpl): DataSource<PeopleHubModel>
+    abstract fun peopleHubDataSource(impl: PeopleHubDataSourceImpl): DataSource<PeopleHubModel>
 
     @Binds
     abstract fun peopleHubViewModelFactoryDataSource(
-        dataSource: PeopleHubViewModelFactoryDataSourceImpl
+        impl: PeopleHubViewModelFactoryDataSourceImpl
     ): DataSource<PeopleHubViewModelFactory>
+
+    @Binds
+    abstract fun peopleNotificationIdentifier(
+        impl: PeopleNotificationIdentifierImpl
+    ): PeopleNotificationIdentifier
+
+    @Binds
+    abstract fun notificationPersonExtractor(
+        pluginImpl: NotificationPersonExtractorPluginBoundary
+    ): NotificationPersonExtractor
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
index c8a3c1a..987b52db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
@@ -17,11 +17,14 @@
 package com.android.systemui.statusbar.notification.people
 
 import android.app.Notification
+import android.content.Context
 import android.graphics.Canvas
 import android.graphics.ColorFilter
 import android.graphics.PixelFormat
 import android.graphics.drawable.BitmapDrawable
 import android.graphics.drawable.Drawable
+import android.os.UserHandle
+import android.service.notification.StatusBarNotification
 import android.util.TypedValue
 import android.view.View
 import android.view.ViewGroup
@@ -30,59 +33,116 @@
 import com.android.internal.widget.MessagingGroup
 import com.android.launcher3.icons.BaseIconFactory
 import com.android.systemui.R
+import com.android.systemui.plugins.NotificationPersonExtractorPlugin
 import com.android.systemui.statusbar.notification.NotificationEntryListener
 import com.android.systemui.statusbar.notification.NotificationEntryManager
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.policy.ExtensionController
 import java.util.ArrayDeque
 import javax.inject.Inject
 import javax.inject.Singleton
 
 private const val MAX_STORED_INACTIVE_PEOPLE = 10
 
-@Singleton
-class PeopleHubDataSourceImpl @Inject constructor(
-    notificationEntryManager: NotificationEntryManager,
-    private val peopleHubManager: PeopleHubManager
-) : DataSource<PeopleHubModel> {
+interface NotificationPersonExtractor {
+    fun extractPerson(sbn: StatusBarNotification): PersonModel?
+    fun extractPersonKey(sbn: StatusBarNotification): String?
+    fun isPersonNotification(sbn: StatusBarNotification): Boolean
+}
 
-    private var dataListener: DataListener<PeopleHubModel>? = null
+@Singleton
+class NotificationPersonExtractorPluginBoundary @Inject constructor(
+    extensionController: ExtensionController,
+    private val context: Context
+) : NotificationPersonExtractor {
+
+    private var plugin: NotificationPersonExtractorPlugin? = null
 
     init {
-        notificationEntryManager.addNotificationEntryListener(object : NotificationEntryListener {
-            override fun onEntryInflated(entry: NotificationEntry, inflatedFlags: Int) =
-                    addVisibleEntry(entry)
+        plugin = extensionController
+                .newExtension(NotificationPersonExtractorPlugin::class.java)
+                .withPlugin(NotificationPersonExtractorPlugin::class.java)
+                .withCallback { extractor ->
+                    plugin = extractor
+                }
+                .build()
+                .get()
+    }
 
-            override fun onEntryReinflated(entry: NotificationEntry) = addVisibleEntry(entry)
+    override fun extractPerson(sbn: StatusBarNotification) =
+            plugin?.extractPerson(sbn)?.let { data ->
+                val badged = addBadgeToDrawable(data.avatar, context, sbn.packageName, sbn.user)
+                PersonModel(data.key, data.name, badged, data.clickIntent)
+            }
 
-            override fun onPostEntryUpdated(entry: NotificationEntry) = addVisibleEntry(entry)
+    override fun extractPersonKey(sbn: StatusBarNotification) = plugin?.extractPersonKey(sbn)
 
-            override fun onEntryRemoved(
-                entry: NotificationEntry,
-                visibility: NotificationVisibility?,
-                removedByUser: Boolean
-            ) = removeVisibleEntry(entry)
-        })
+    override fun isPersonNotification(sbn: StatusBarNotification): Boolean =
+            plugin?.isPersonNotification(sbn) ?: false
+}
+
+@Singleton
+class PeopleHubDataSourceImpl @Inject constructor(
+    private val notificationEntryManager: NotificationEntryManager,
+    private val peopleHubManager: PeopleHubManager,
+    private val extractor: NotificationPersonExtractor
+) : DataSource<PeopleHubModel> {
+
+    private val dataListeners = mutableListOf<DataListener<PeopleHubModel>>()
+
+    private val notificationEntryListener = object : NotificationEntryListener {
+        override fun onEntryInflated(entry: NotificationEntry, inflatedFlags: Int) =
+                addVisibleEntry(entry)
+
+        override fun onEntryReinflated(entry: NotificationEntry) = addVisibleEntry(entry)
+
+        override fun onPostEntryUpdated(entry: NotificationEntry) = addVisibleEntry(entry)
+
+        override fun onEntryRemoved(
+            entry: NotificationEntry,
+            visibility: NotificationVisibility?,
+            removedByUser: Boolean
+        ) = removeVisibleEntry(entry)
     }
 
     private fun removeVisibleEntry(entry: NotificationEntry) {
-        if (entry.extractPersonKey()?.let(peopleHubManager::removeActivePerson) == true) {
+        val key = extractor.extractPersonKey(entry.sbn) ?: entry.extractPersonKey()
+        if (key?.let(peopleHubManager::removeActivePerson) == true) {
             updateUi()
         }
     }
 
     private fun addVisibleEntry(entry: NotificationEntry) {
-        if (entry.extractPerson()?.let(peopleHubManager::addActivePerson) == true) {
+        val personModel = extractor.extractPerson(entry.sbn) ?: entry.extractPerson()
+        if (personModel?.let(peopleHubManager::addActivePerson) == true) {
             updateUi()
         }
     }
 
-    override fun setListener(listener: DataListener<PeopleHubModel>) {
-        this.dataListener = listener
-        updateUi()
+    override fun registerListener(listener: DataListener<PeopleHubModel>): Subscription {
+        val registerWithNotificationEntryManager = dataListeners.isEmpty()
+        dataListeners.add(listener)
+        if (registerWithNotificationEntryManager) {
+            notificationEntryManager.addNotificationEntryListener(notificationEntryListener)
+        } else {
+            listener.onDataChanged(peopleHubManager.getPeopleHubModel())
+        }
+        return object : Subscription {
+            override fun unsubscribe() {
+                dataListeners.remove(listener)
+                if (dataListeners.isEmpty()) {
+                    notificationEntryManager
+                            .removeNotificationEntryListener(notificationEntryListener)
+                }
+            }
+        }
     }
 
     private fun updateUi() {
-        dataListener?.onDataChanged(peopleHubManager.getPeopleHubModel())
+        val model = peopleHubManager.getPeopleHubModel()
+        for (listener in dataListeners) {
+            listener.onDataChanged(model)
+        }
     }
 }
 
@@ -124,19 +184,25 @@
     if (!isMessagingNotification()) {
         return null
     }
-
-    val clickIntent = sbn.notification.contentIntent
+    val clickIntent = sbn.notification.contentIntent ?: return null
     val extras = sbn.notification.extras
     val name = extras.getString(Notification.EXTRA_CONVERSATION_TITLE)
             ?: extras.getString(Notification.EXTRA_TITLE)
             ?: return null
     val drawable = extractAvatarFromRow(this) ?: return null
+    val badgedAvatar = addBadgeToDrawable(drawable, row.context, sbn.packageName, sbn.user)
+    return PersonModel(key, name, badgedAvatar, clickIntent)
+}
 
-    val context = row.context
+private fun addBadgeToDrawable(
+    drawable: Drawable,
+    context: Context,
+    packageName: String,
+    user: UserHandle
+): Drawable {
     val pm = context.packageManager
-    val appInfo = pm.getApplicationInfoAsUser(sbn.packageName, 0, sbn.user)
-
-    val badgedAvatar = object : Drawable() {
+    val appInfo = pm.getApplicationInfoAsUser(packageName, 0, user)
+    return object : Drawable() {
         override fun draw(canvas: Canvas) {
             val iconBounds = getBounds()
             val factory = object : BaseIconFactory(
@@ -146,7 +212,7 @@
                     true) {}
             val badge = factory.createBadgedIconBitmap(
                     appInfo.loadIcon(pm),
-                    sbn.user,
+                    user,
                     true,
                     appInfo.isInstantApp,
                     null)
@@ -156,7 +222,7 @@
                         colorFilter = drawable.colorFilter
                         val badgeWidth = TypedValue.applyDimension(
                                 TypedValue.COMPLEX_UNIT_DIP,
-                                16f,
+                                15f,
                                 context.resources.displayMetrics
                         ).toInt()
                         setBounds(
@@ -181,8 +247,6 @@
         @PixelFormat.Opacity
         override fun getOpacity(): Int = PixelFormat.OPAQUE
     }
-
-    return PersonModel(key, name, badgedAvatar, clickIntent)
 }
 
 private fun extractAvatarFromRow(entry: NotificationEntry): Drawable? =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt
index 8d1253b..5c35408 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt
@@ -60,8 +60,9 @@
     private val dataSource: DataSource<@JvmSuppressWildcards PeopleHubViewModelFactory>
 ) : PeopleHubSectionFooterViewAdapter {
 
-    override fun bindView(viewBoundary: PeopleHubSectionFooterViewBoundary) =
-            dataSource.setListener(PeopleHubDataListenerImpl(viewBoundary))
+    override fun bindView(viewBoundary: PeopleHubSectionFooterViewBoundary) {
+        dataSource.registerListener(PeopleHubDataListenerImpl(viewBoundary))
+    }
 }
 
 private class PeopleHubDataListenerImpl(
@@ -92,8 +93,8 @@
     private val dataSource: DataSource<@JvmSuppressWildcards PeopleHubModel>
 ) : DataSource<PeopleHubViewModelFactory> {
 
-    override fun setListener(listener: DataListener<PeopleHubViewModelFactory>) =
-            dataSource.setListener(PeopleHubModelListenerImpl(activityStarter, listener))
+    override fun registerListener(listener: DataListener<PeopleHubViewModelFactory>) =
+            dataSource.registerListener(PeopleHubModelListenerImpl(activityStarter, listener))
 }
 
 private class PeopleHubModelListenerImpl(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
new file mode 100644
index 0000000..78eaf3e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.people
+
+import android.app.Notification
+import android.service.notification.StatusBarNotification
+import javax.inject.Inject
+import javax.inject.Singleton
+
+interface PeopleNotificationIdentifier {
+    fun isPeopleNotification(sbn: StatusBarNotification): Boolean
+}
+
+@Singleton
+class PeopleNotificationIdentifierImpl @Inject constructor(
+    private val personExtractor: NotificationPersonExtractor
+) : PeopleNotificationIdentifier {
+
+    override fun isPeopleNotification(sbn: StatusBarNotification) =
+            sbn.notification.notificationStyle == Notification.MessagingStyle::class.java ||
+                    personExtractor.isPersonNotification(sbn)
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/ViewPipeline.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/ViewPipeline.kt
index 33e3bb8..3ca3792 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/ViewPipeline.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/ViewPipeline.kt
@@ -28,10 +28,17 @@
 
 /** Boundary between a View and data pipeline, as seen by the View. */
 interface DataSource<out T> {
-    fun setListener(listener: DataListener<T>)
+    fun registerListener(listener: DataListener<T>): Subscription
+}
+
+/** Represents a registration with a [DataSource]. */
+interface Subscription {
+    /** Removes the previously registered [DataListener] from the [DataSource] */
+    fun unsubscribe()
 }
 
 /** Transform all data coming out of this [DataSource] using the given [mapper]. */
 fun <S, T> DataSource<S>.map(mapper: (S) -> T): DataSource<T> = object : DataSource<T> {
-    override fun setListener(listener: DataListener<T>) = setListener(listener.contraMap(mapper))
+    override fun registerListener(listener: DataListener<T>) =
+            registerListener(listener.contraMap(mapper))
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
index 9bc0ca4..d0122c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
@@ -28,7 +28,6 @@
 import android.media.session.PlaybackState;
 import android.metrics.LogMaker;
 import android.os.Handler;
-import android.provider.Settings;
 import android.text.format.DateUtils;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -48,6 +47,7 @@
 import com.android.systemui.statusbar.TransformableView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
+import com.android.systemui.util.Utils;
 
 import java.util.Timer;
 import java.util.TimerTask;
@@ -182,8 +182,7 @@
         final MediaSession.Token token = mRow.getEntry().getSbn().getNotification().extras
                 .getParcelable(Notification.EXTRA_MEDIA_SESSION);
 
-        int flag = Settings.System.getInt(mContext.getContentResolver(), "qs_media_player", 0);
-        if (flag == 1) {
+        if (Utils.useQsMediaPlayer(mContext)) {
             StatusBarWindowController ctrl = Dependency.get(StatusBarWindowController.class);
             QuickQSPanel panel = ctrl.getStatusBarView().findViewById(
                     com.android.systemui.R.id.quick_qs_panel);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
index bd87d77..54d4066 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
@@ -131,6 +131,7 @@
         }
         mInitialized = true;
         reinflateViews(layoutInflater);
+        mPeopleHubViewAdapter.bindView(mPeopleHubViewBoundary);
         mConfigurationController.addCallback(mConfigurationListener);
     }
 
@@ -172,10 +173,6 @@
         if (oldPeopleHubPos != -1) {
             mParent.addView(mPeopleHubView, oldPeopleHubPos);
         }
-
-        if (!mInitialized) {
-            mPeopleHubViewAdapter.bindView(mPeopleHubViewBoundary);
-        }
     }
 
     /** Listener for when the "clear all" buttton is clciked on the gentle notification header. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 548afd5..865d7e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.content.Context;
+import android.content.res.Resources;
 import android.hardware.biometrics.BiometricSourceType;
 import android.metrics.LogMaker;
 import android.os.Handler;
@@ -34,25 +35,33 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.Dependency;
+import com.android.systemui.DumpController;
+import com.android.systemui.Dumpable;
+import com.android.systemui.dagger.qualifiers.MainResources;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
+import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
 /**
  * Controller which coordinates all the biometric unlocking actions with the UI.
  */
-public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
+@Singleton
+public class BiometricUnlockController extends KeyguardUpdateMonitorCallback implements Dumpable {
 
-    private static final String TAG = "BiometricUnlockController";
+    private static final String TAG = "BiometricUnlockCtrl";
     private static final boolean DEBUG_BIO_WAKELOCK = KeyguardConstants.DEBUG_BIOMETRIC_WAKELOCK;
     private static final long BIOMETRIC_WAKELOCK_TIMEOUT_MS = 15 * 1000;
-    private static final String BIOMETRIC_WAKE_LOCK_NAME = "wake-and-unlock wakelock";
+    private static final String BIOMETRIC_WAKE_LOCK_NAME = "wake-and-unlock:wakelock";
 
     @IntDef(prefix = { "MODE_" }, value = {
             MODE_NONE,
@@ -145,31 +154,16 @@
     private boolean mHasScreenTurnedOnSinceAuthenticating;
     private boolean mFadedAwayAfterWakeAndUnlock;
 
-    private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
+    private final MetricsLogger mMetricsLogger;
 
-    public BiometricUnlockController(
-            Context context,
-            DozeScrimController dozeScrimController,
-            KeyguardViewMediator keyguardViewMediator,
-            ScrimController scrimController,
-            StatusBar statusBar,
-            KeyguardStateController keyguardStateController, Handler handler,
-            KeyguardUpdateMonitor keyguardUpdateMonitor,
-            KeyguardBypassController keyguardBypassController,
-            DozeParameters dozeParameters) {
-        this(context, dozeScrimController, keyguardViewMediator, scrimController, statusBar,
-                keyguardStateController, handler, keyguardUpdateMonitor,
-                context.getResources()
-                        .getInteger(com.android.internal.R.integer.config_wakeUpDelayDoze),
-                keyguardBypassController, dozeParameters);
-    }
-
-    @VisibleForTesting
-    protected BiometricUnlockController(Context context, DozeScrimController dozeScrimController,
+    @Inject
+    public BiometricUnlockController(Context context, DozeScrimController dozeScrimController,
             KeyguardViewMediator keyguardViewMediator, ScrimController scrimController,
             StatusBar statusBar, KeyguardStateController keyguardStateController, Handler handler,
-            KeyguardUpdateMonitor keyguardUpdateMonitor, int wakeUpDelay,
-            KeyguardBypassController keyguardBypassController, DozeParameters dozeParameters) {
+            KeyguardUpdateMonitor keyguardUpdateMonitor,
+            @MainResources Resources resources,
+            KeyguardBypassController keyguardBypassController, DozeParameters dozeParameters,
+            MetricsLogger metricsLogger, DumpController dumpController) {
         mContext = context;
         mPowerManager = context.getSystemService(PowerManager.class);
         mUpdateMonitor = keyguardUpdateMonitor;
@@ -185,9 +179,11 @@
         mStatusBar = statusBar;
         mKeyguardStateController = keyguardStateController;
         mHandler = handler;
-        mWakeUpDelay = wakeUpDelay;
+        mWakeUpDelay = resources.getInteger(com.android.internal.R.integer.config_wakeUpDelayDoze);
         mKeyguardBypassController = keyguardBypassController;
         mKeyguardBypassController.setUnlockController(this);
+        mMetricsLogger = metricsLogger;
+        dumpController.registerDumpable(this);
     }
 
     public void setStatusBarKeyguardViewManager(
@@ -551,7 +547,8 @@
         return mHasScreenTurnedOnSinceAuthenticating;
     }
 
-    public void dump(PrintWriter pw) {
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println(" BiometricUnlockController:");
         pw.print("   mMode="); pw.println(mMode);
         pw.print("   mWakeLock="); pw.println(mWakeLock);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
index fce1dcc..c273108 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -203,10 +203,16 @@
             mFadeAnimator.addUpdateListener(mAlphaListener);
             mFadeAnimator.start();
         } else {
-            mAlpha = alpha;
-            final int N = mViews.size();
-            for (int i = 0; i < N; i++) {
-                mViews.get(i).setAlpha(alpha);
+            // Discretize the alpha updates to prevent too frequent updates when there is a long
+            // alpha animation
+            int prevAlpha = (int) (getAlpha() * 255);
+            int nextAlpha = (int) (alpha * 255);
+            if (prevAlpha != nextAlpha) {
+                mAlpha = nextAlpha / 255f;
+                final int N = mViews.size();
+                for (int i = 0; i < N; i++) {
+                    mViews.get(i).setAlpha(mAlpha);
+                }
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index e78b85e..0092cc9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -83,7 +83,7 @@
         mNetworkController = Dependency.get(NetworkController.class);
         mStatusBarStateController = Dependency.get(StatusBarStateController.class);
         mStatusBarComponent = SysUiServiceProvider.getComponent(getContext(), StatusBar.class);
-        mCommandQueue = SysUiServiceProvider.getComponent(getContext(), CommandQueue.class);
+        mCommandQueue = Dependency.get(CommandQueue.class);
     }
 
     @Override
@@ -100,7 +100,8 @@
             mStatusBar.restoreHierarchyState(
                     savedInstanceState.getSparseParcelableArray(EXTRA_PANEL_STATE));
         }
-        mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons));
+        mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons),
+                Dependency.get(CommandQueue.class));
         mDarkIconManager.setShouldLog(true);
         Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
         mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
index ac58e68..ef0f7cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
@@ -26,6 +26,7 @@
 
 import com.android.systemui.R;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.statusbar.CommandQueue;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -51,11 +52,11 @@
     /**
      */
     @Inject
-    public DarkIconDispatcherImpl(Context context) {
+    public DarkIconDispatcherImpl(Context context, CommandQueue commandQueue) {
         mDarkModeIconColorSingleTone = context.getColor(R.color.dark_mode_icon_color_single_tone);
         mLightModeIconColorSingleTone = context.getColor(R.color.light_mode_icon_color_single_tone);
 
-        mTransitionsController = new LightBarTransitionsController(context, this);
+        mTransitionsController = new LightBarTransitionsController(context, this, commandQueue);
     }
 
     public LightBarTransitionsController getTransitionsController() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 50d33a7..bc48235 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -24,7 +24,6 @@
 import android.provider.Settings;
 import android.util.MathUtils;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
 import com.android.systemui.dagger.qualifiers.MainResources;
 import com.android.systemui.doze.AlwaysOnDisplayPolicy;
@@ -188,12 +187,7 @@
             return;
         }
         mControlScreenOffAnimation = controlScreenOffAnimation;
-        getPowerManager().setDozeAfterScreenOff(!controlScreenOffAnimation);
-    }
-
-    @VisibleForTesting
-    protected PowerManager getPowerManager() {
-        return mPowerManager;
+        mPowerManager.setDozeAfterScreenOff(!controlScreenOffAnimation);
     }
 
     private boolean getBoolean(String propName, int resId) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index fe3c04e..1ecc489 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -29,10 +29,12 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 
 import javax.inject.Inject;
+import javax.inject.Singleton;
 
 /**
  * Controller which handles all the doze animations of the scrims.
  */
+@Singleton
 public class DozeScrimController implements StateListener {
     private static final String TAG = "DozeScrimController";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
new file mode 100644
index 0000000..2854355
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -0,0 +1,465 @@
+/*
+ * 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.phone;
+
+import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
+import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
+
+import android.annotation.NonNull;
+import android.os.Bundle;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.doze.DozeEvent;
+import com.android.systemui.doze.DozeHost;
+import com.android.systemui.doze.DozeLog;
+import com.android.systemui.doze.DozeReceiver;
+import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.statusbar.PulseExpansionHandler;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+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.policy.BatteryController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+
+import java.util.ArrayList;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import dagger.Lazy;
+
+/**
+ * Implementation of DozeHost for SystemUI.
+ */
+@Singleton
+public final class DozeServiceHost implements DozeHost {
+    private static final String TAG = "DozeServiceHost";
+    private final ArrayList<Callback> mCallbacks = new ArrayList<>();
+    private final DozeLog mDozeLog;
+    private final PowerManager mPowerManager;
+    private boolean mAnimateWakeup;
+    private boolean mAnimateScreenOff;
+    private boolean mIgnoreTouchWhilePulsing;
+    private Runnable mPendingScreenOffCallback;
+    @VisibleForTesting
+    boolean mWakeLockScreenPerformsAuth = SystemProperties.getBoolean(
+            "persist.sysui.wake_performs_auth", true);
+    private boolean mDozingRequested;
+    private boolean mDozing;
+    private boolean mPulsing;
+    private WakefulnessLifecycle mWakefulnessLifecycle;
+    private final SysuiStatusBarStateController mStatusBarStateController;
+    private final DeviceProvisionedController mDeviceProvisionedController;
+    private final HeadsUpManagerPhone mHeadsUpManagerPhone;
+    private final BatteryController mBatteryController;
+    private final ScrimController mScrimController;
+    private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
+    private BiometricUnlockController mBiometricUnlockController;
+    private final KeyguardViewMediator mKeyguardViewMediator;
+    private final AssistManager mAssistManager;
+    private final DozeScrimController mDozeScrimController;
+    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private final VisualStabilityManager mVisualStabilityManager;
+    private final PulseExpansionHandler mPulseExpansionHandler;
+    private final StatusBarWindowController mStatusBarWindowController;
+    private final NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
+    private NotificationIconAreaController mNotificationIconAreaController;
+    private StatusBarWindowViewController mStatusBarWindowViewController;
+    private StatusBarWindowView mStatusBarWindow;
+    private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    private NotificationPanelView mNotificationPanel;
+    private View mAmbientIndicationContainer;
+    private StatusBar mStatusBar;
+
+    @Inject
+    public DozeServiceHost(DozeLog dozeLog, PowerManager powerManager,
+            WakefulnessLifecycle wakefulnessLifecycle,
+            SysuiStatusBarStateController statusBarStateController,
+            DeviceProvisionedController deviceProvisionedController,
+            HeadsUpManagerPhone headsUpManagerPhone, BatteryController batteryController,
+            ScrimController scrimController,
+            Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
+            KeyguardViewMediator keyguardViewMediator,
+            AssistManager assistManager,
+            DozeScrimController dozeScrimController, KeyguardUpdateMonitor keyguardUpdateMonitor,
+            VisualStabilityManager visualStabilityManager,
+            PulseExpansionHandler pulseExpansionHandler,
+            StatusBarWindowController statusBarWindowController,
+            NotificationWakeUpCoordinator notificationWakeUpCoordinator) {
+        super();
+        mDozeLog = dozeLog;
+        mPowerManager = powerManager;
+        mWakefulnessLifecycle = wakefulnessLifecycle;
+        mStatusBarStateController = statusBarStateController;
+        mDeviceProvisionedController = deviceProvisionedController;
+        mHeadsUpManagerPhone = headsUpManagerPhone;
+        mBatteryController = batteryController;
+        mScrimController = scrimController;
+        mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
+        mKeyguardViewMediator = keyguardViewMediator;
+        mAssistManager = assistManager;
+        mDozeScrimController = dozeScrimController;
+        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+        mVisualStabilityManager = visualStabilityManager;
+        mPulseExpansionHandler = pulseExpansionHandler;
+        mStatusBarWindowController = statusBarWindowController;
+        mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
+    }
+
+    // TODO: we should try to not pass status bar in here if we can avoid it.
+
+    /**
+     * Initialize instance with objects only available later during execution.
+     */
+    public void initialize(StatusBar statusBar,
+            NotificationIconAreaController notificationIconAreaController,
+            StatusBarWindowViewController statusBarWindowViewController,
+            StatusBarWindowView statusBarWindow,
+            StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+            NotificationPanelView notificationPanel, View ambientIndicationContainer) {
+        mStatusBar = statusBar;
+        mNotificationIconAreaController = notificationIconAreaController;
+        mStatusBarWindowViewController = statusBarWindowViewController;
+        mStatusBarWindow = statusBarWindow;
+        mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+        mNotificationPanel = notificationPanel;
+        mAmbientIndicationContainer = ambientIndicationContainer;
+        mBiometricUnlockController = mBiometricUnlockControllerLazy.get();
+    }
+
+    @Override
+    public String toString() {
+        return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]";
+    }
+
+    void firePowerSaveChanged(boolean active) {
+        for (Callback callback : mCallbacks) {
+            callback.onPowerSaveChanged(active);
+        }
+    }
+
+    void fireNotificationPulse(NotificationEntry entry) {
+        Runnable pulseSuppressedListener = () -> {
+            entry.setPulseSuppressed(true);
+            mNotificationIconAreaController.updateAodNotificationIcons();
+        };
+        for (Callback callback : mCallbacks) {
+            callback.onNotificationAlerted(pulseSuppressedListener);
+        }
+    }
+
+    boolean getDozingRequested() {
+        return mDozingRequested;
+    }
+
+    boolean isPulsing() {
+        return mPulsing;
+    }
+
+
+    @Override
+    public void addCallback(@NonNull Callback callback) {
+        mCallbacks.add(callback);
+    }
+
+    @Override
+    public void removeCallback(@NonNull Callback callback) {
+        mCallbacks.remove(callback);
+    }
+
+    @Override
+    public void startDozing() {
+        if (!mDozingRequested) {
+            mDozingRequested = true;
+            mDozeLog.traceDozing(mDozing);
+            updateDozing();
+            mStatusBar.updateIsKeyguard();
+        }
+    }
+
+    void updateDozing() {
+        // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked.
+        boolean
+                dozing =
+                mDozingRequested && mStatusBarStateController.getState() == StatusBarState.KEYGUARD
+                        || mBiometricUnlockController.getMode()
+                        == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
+        // When in wake-and-unlock we may not have received a change to StatusBarState
+        // but we still should not be dozing, manually set to false.
+        if (mBiometricUnlockController.getMode()
+                == BiometricUnlockController.MODE_WAKE_AND_UNLOCK) {
+            dozing = false;
+        }
+
+
+        mStatusBarStateController.setIsDozing(dozing);
+    }
+
+    @Override
+    public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) {
+        if (reason == DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS) {
+            mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
+                                 "com.android.systemui:LONG_PRESS");
+            mAssistManager.startAssist(new Bundle());
+            return;
+        }
+
+        if (reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
+            mScrimController.setWakeLockScreenSensorActive(true);
+        }
+
+        if (reason == DozeEvent.PULSE_REASON_DOCKING && mStatusBarWindow != null) {
+            mStatusBarWindowViewController.suppressWakeUpGesture(true);
+        }
+
+        boolean passiveAuthInterrupt = reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN
+                        && mWakeLockScreenPerformsAuth;
+        // Set the state to pulsing, so ScrimController will know what to do once we ask it to
+        // execute the transition. The pulse callback will then be invoked when the scrims
+        // are black, indicating that StatusBar is ready to present the rest of the UI.
+        mPulsing = true;
+        mDozeScrimController.pulse(new PulseCallback() {
+            @Override
+            public void onPulseStarted() {
+                callback.onPulseStarted();
+                mStatusBar.updateNotificationPanelTouchState();
+                setPulsing(true);
+            }
+
+            @Override
+            public void onPulseFinished() {
+                mPulsing = false;
+                callback.onPulseFinished();
+                mStatusBar.updateNotificationPanelTouchState();
+                mScrimController.setWakeLockScreenSensorActive(false);
+                if (mStatusBarWindow != null) {
+                    mStatusBarWindowViewController.suppressWakeUpGesture(false);
+                }
+                setPulsing(false);
+            }
+
+            private void setPulsing(boolean pulsing) {
+                mStatusBarStateController.setPulsing(pulsing);
+                mStatusBarKeyguardViewManager.setPulsing(pulsing);
+                mKeyguardViewMediator.setPulsing(pulsing);
+                mNotificationPanel.setPulsing(pulsing);
+                mVisualStabilityManager.setPulsing(pulsing);
+                mStatusBarWindowViewController.setPulsing(pulsing);
+                mIgnoreTouchWhilePulsing = false;
+                if (mKeyguardUpdateMonitor != null && passiveAuthInterrupt) {
+                    mKeyguardUpdateMonitor.onAuthInterruptDetected(pulsing /* active */);
+                }
+                mStatusBar.updateScrimController();
+                mPulseExpansionHandler.setPulsing(pulsing);
+                mNotificationWakeUpCoordinator.setPulsing(pulsing);
+            }
+        }, reason);
+        // DozeScrimController is in pulse state, now let's ask ScrimController to start
+        // pulsing and draw the black frame, if necessary.
+        mStatusBar.updateScrimController();
+    }
+
+    @Override
+    public void stopDozing() {
+        if (mDozingRequested) {
+            mDozingRequested = false;
+            mDozeLog.traceDozing(mDozing);
+            updateDozing();
+        }
+    }
+
+    @Override
+    public void onIgnoreTouchWhilePulsing(boolean ignore) {
+        if (ignore != mIgnoreTouchWhilePulsing) {
+            mDozeLog.tracePulseTouchDisabledByProx(ignore);
+        }
+        mIgnoreTouchWhilePulsing = ignore;
+        if (mDozing && ignore) {
+            mStatusBarWindowViewController.cancelCurrentTouch();
+        }
+    }
+
+    @Override
+    public void dozeTimeTick() {
+        mNotificationPanel.dozeTimeTick();
+        if (mAmbientIndicationContainer instanceof DozeReceiver) {
+            ((DozeReceiver) mAmbientIndicationContainer).dozeTimeTick();
+        }
+    }
+
+    @Override
+    public boolean isPowerSaveActive() {
+        return mBatteryController.isAodPowerSave();
+    }
+
+    @Override
+    public boolean isPulsingBlocked() {
+        return mBiometricUnlockController.getMode()
+                == BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
+    }
+
+    @Override
+    public boolean isProvisioned() {
+        return mDeviceProvisionedController.isDeviceProvisioned()
+                && mDeviceProvisionedController.isCurrentUserSetup();
+    }
+
+    @Override
+    public boolean isBlockingDoze() {
+        if (mBiometricUnlockController.hasPendingAuthentication()) {
+            Log.i(StatusBar.TAG, "Blocking AOD because fingerprint has authenticated");
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void extendPulse(int reason) {
+        if (reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
+            mScrimController.setWakeLockScreenSensorActive(true);
+        }
+        if (mDozeScrimController.isPulsing() && mHeadsUpManagerPhone.hasNotifications()) {
+            mHeadsUpManagerPhone.extendHeadsUp();
+        } else {
+            mDozeScrimController.extendPulse();
+        }
+    }
+
+    @Override
+    public void stopPulsing() {
+        if (mDozeScrimController.isPulsing()) {
+            mDozeScrimController.pulseOutNow();
+        }
+    }
+
+    @Override
+    public void setAnimateWakeup(boolean animateWakeup) {
+        if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_AWAKE
+                || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_WAKING) {
+            // Too late to change the wakeup animation.
+            return;
+        }
+        mAnimateWakeup = animateWakeup;
+    }
+
+    @Override
+    public void setAnimateScreenOff(boolean animateScreenOff) {
+        mAnimateScreenOff = animateScreenOff;
+    }
+
+    @Override
+    public void onSlpiTap(float screenX, float screenY) {
+        if (screenX > 0 && screenY > 0 && mAmbientIndicationContainer != null
+                && mAmbientIndicationContainer.getVisibility() == View.VISIBLE) {
+            int[] locationOnScreen = new int[2];
+            mAmbientIndicationContainer.getLocationOnScreen(locationOnScreen);
+            float viewX = screenX - locationOnScreen[0];
+            float viewY = screenY - locationOnScreen[1];
+            if (0 <= viewX && viewX <= mAmbientIndicationContainer.getWidth()
+                    && 0 <= viewY && viewY <= mAmbientIndicationContainer.getHeight()) {
+
+                // Dispatch a tap
+                long now = SystemClock.elapsedRealtime();
+                MotionEvent ev = MotionEvent.obtain(
+                        now, now, MotionEvent.ACTION_DOWN, screenX, screenY, 0);
+                mAmbientIndicationContainer.dispatchTouchEvent(ev);
+                ev.recycle();
+                ev = MotionEvent.obtain(
+                        now, now, MotionEvent.ACTION_UP, screenX, screenY, 0);
+                mAmbientIndicationContainer.dispatchTouchEvent(ev);
+                ev.recycle();
+            }
+        }
+    }
+
+    @Override
+    public void setDozeScreenBrightness(int value) {
+        mStatusBarWindowController.setDozeScreenBrightness(value);
+    }
+
+    @Override
+    public void setAodDimmingScrim(float scrimOpacity) {
+        mScrimController.setAodFrontScrimAlpha(scrimOpacity);
+    }
+
+
+
+    @Override
+    public void prepareForGentleSleep(Runnable onDisplayOffCallback) {
+        if (mPendingScreenOffCallback != null) {
+            Log.w(TAG, "Overlapping onDisplayOffCallback. Ignoring previous one.");
+        }
+        mPendingScreenOffCallback = onDisplayOffCallback;
+        mStatusBar.updateScrimController();
+    }
+
+    @Override
+    public void cancelGentleSleep() {
+        mPendingScreenOffCallback = null;
+        if (mScrimController.getState() == ScrimState.OFF) {
+            mStatusBar.updateScrimController();
+        }
+    }
+
+    /**
+     * When the dozing host is waiting for scrims to fade out to change the display state.
+     */
+    boolean hasPendingScreenOffCallback() {
+        return mPendingScreenOffCallback != null;
+    }
+
+    /**
+     * Executes an nullifies the pending display state callback.
+     *
+     * @see #hasPendingScreenOffCallback()
+     * @see #prepareForGentleSleep(Runnable)
+     */
+    void executePendingScreenOffCallback() {
+        if (mPendingScreenOffCallback == null) {
+            return;
+        }
+        mPendingScreenOffCallback.run();
+        mPendingScreenOffCallback = null;
+    }
+
+    boolean shouldAnimateWakeup() {
+        return mAnimateWakeup;
+    }
+
+    boolean shouldAnimateScreenOff() {
+        return mAnimateScreenOff;
+    }
+
+    public void setDozing(boolean dozing) {
+        mDozing = dozing;
+    }
+
+    boolean getIgnoreTouchWhilePulsing() {
+        return mIgnoreTouchWhilePulsing;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index ce96005..8e5a912 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static com.android.systemui.SysUiServiceProvider.getComponent;
-
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.view.DisplayCutout;
@@ -94,14 +92,14 @@
 
     public HeadsUpAppearanceController(
             NotificationIconAreaController notificationIconAreaController,
-            HeadsUpManagerPhone headsUpManager,
-            View statusbarView,
+            HeadsUpManagerPhone headsUpManager, View statusbarView,
             SysuiStatusBarStateController statusBarStateController,
             KeyguardBypassController keyguardBypassController,
             KeyguardStateController keyguardStateController,
-            NotificationWakeUpCoordinator wakeUpCoordinator) {
+            NotificationWakeUpCoordinator wakeUpCoordinator, CommandQueue commandQueue) {
         this(notificationIconAreaController, headsUpManager, statusBarStateController,
                 keyguardBypassController, wakeUpCoordinator, keyguardStateController,
+                commandQueue,
                 statusbarView.findViewById(R.id.heads_up_status_bar_view),
                 statusbarView.findViewById(R.id.notification_stack_scroller),
                 statusbarView.findViewById(R.id.notification_panel),
@@ -118,6 +116,7 @@
             KeyguardBypassController bypassController,
             NotificationWakeUpCoordinator wakeUpCoordinator,
             KeyguardStateController keyguardStateController,
+            CommandQueue commandQueue,
             HeadsUpStatusBarView headsUpStatusBarView,
             NotificationStackScrollLayout stackScroller,
             NotificationPanelView panelView,
@@ -161,7 +160,7 @@
         mStatusBarStateController = stateController;
         mWakeUpCoordinator = wakeUpCoordinator;
         wakeUpCoordinator.addListener(this);
-        mCommandQueue = getComponent(headsUpStatusBarView.getContext(), CommandQueue.class);
+        mCommandQueue = commandQueue;
         mKeyguardStateController = keyguardStateController;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index dd200da..7f31f3d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -77,9 +77,12 @@
                 ExpandableView child = mCallback.getChildAtRawPosition(x, y);
                 mTouchingHeadsUpView = false;
                 if (child instanceof ExpandableNotificationRow) {
-                    mPickedChild = (ExpandableNotificationRow) child;
+                    ExpandableNotificationRow pickedChild = (ExpandableNotificationRow) child;
                     mTouchingHeadsUpView = !mCallback.isExpanded()
-                            && mPickedChild.isHeadsUp() && mPickedChild.isPinned();
+                            && pickedChild.isHeadsUp() && pickedChild.isPinned();
+                    if (mTouchingHeadsUpView) {
+                        mPickedChild = pickedChild;
+                    }
                 } else if (child == null && !mCallback.isExpanded()) {
                     // We might touch above the visible heads up child, but then we still would
                     // like to capture it.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index aca7f44..f7d52b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -20,17 +20,20 @@
 import android.content.pm.PackageManager
 import android.hardware.biometrics.BiometricSourceType
 import android.provider.Settings
+import com.android.systemui.DumpController
+import com.android.systemui.Dumpable
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.NotificationLockscreenUserManager
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.tuner.TunerService
+import java.io.FileDescriptor
 import java.io.PrintWriter
 import javax.inject.Inject
 import javax.inject.Singleton
 
 @Singleton
-class KeyguardBypassController {
+class KeyguardBypassController : Dumpable {
 
     private val mKeyguardStateController: KeyguardStateController
     private val statusBarStateController: StatusBarStateController
@@ -68,7 +71,8 @@
         tunerService: TunerService,
         statusBarStateController: StatusBarStateController,
         lockscreenUserManager: NotificationLockscreenUserManager,
-        keyguardStateController: KeyguardStateController
+        keyguardStateController: KeyguardStateController,
+        dumpController: DumpController
     ) {
         this.mKeyguardStateController = keyguardStateController
         this.statusBarStateController = statusBarStateController
@@ -78,6 +82,7 @@
             return
         }
 
+        dumpController.registerDumpable("KeyguardBypassController", this)
         statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
             override fun onStateChanged(newState: Int) {
                 if (newState != StatusBarState.KEYGUARD) {
@@ -155,16 +160,16 @@
         pendingUnlockType = null
     }
 
-    fun dump(pw: PrintWriter) {
+    override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
         pw.println("KeyguardBypassController:")
-        pw.print("  pendingUnlockType: "); pw.println(pendingUnlockType)
-        pw.print("  bypassEnabled: "); pw.println(bypassEnabled)
-        pw.print("  canBypass: "); pw.println(canBypass())
-        pw.print("  bouncerShowing: "); pw.println(bouncerShowing)
-        pw.print("  isPulseExpanding: "); pw.println(isPulseExpanding)
-        pw.print("  launchingAffordance: "); pw.println(launchingAffordance)
-        pw.print("  qSExpanded: "); pw.println(qSExpanded)
-        pw.print("  hasFaceFeature: "); pw.println(hasFaceFeature)
+        pw.println("  pendingUnlockType: $pendingUnlockType")
+        pw.println("  bypassEnabled: $bypassEnabled")
+        pw.println("  canBypass: ${canBypass()}")
+        pw.println("  bouncerShowing: $bouncerShowing")
+        pw.println("  isPulseExpanding: $isPulseExpanding")
+        pw.println("  launchingAffordance: $launchingAffordance")
+        pw.println("  qSExpanded: $qSExpanded")
+        pw.println("  hasFaceFeature: $hasFaceFeature")
     }
 
     companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 179375e..4e91e4c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -240,7 +240,7 @@
      * @return Alpha from 0 to 1.
      */
     private float getClockAlpha(int y) {
-        float alphaKeyguard = Math.max(0, y / Math.max(1f, getExpandedPreferredClockY()));
+        float alphaKeyguard = Math.max(0, y / Math.max(1f, getClockY(1f)));
         alphaKeyguard = Interpolators.ACCELERATE.getInterpolation(alphaKeyguard);
         return MathUtils.lerp(alphaKeyguard, 1f, mDarkAmount);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
index d9de59e..2258c77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
@@ -21,22 +21,27 @@
 import android.hardware.TriggerEventListener
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
-import com.android.systemui.Dependency
+import com.android.systemui.DumpController
+import com.android.systemui.Dumpable
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.util.Assert
 import com.android.systemui.util.sensors.AsyncSensorManager
+import java.io.FileDescriptor
+import java.io.PrintWriter
 
 class KeyguardLiftController constructor(
     private val statusBarStateController: StatusBarStateController,
-    private val asyncSensorManager: AsyncSensorManager
-) : StatusBarStateController.StateListener, KeyguardUpdateMonitorCallback() {
+    private val asyncSensorManager: AsyncSensorManager,
+    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+    dumpController: DumpController
+) : StatusBarStateController.StateListener, Dumpable, KeyguardUpdateMonitorCallback() {
 
-    private val keyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor::class.java)
     private val pickupSensor = asyncSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE)
     private var isListening = false
     private var bouncerVisible = false
 
     init {
+        dumpController.registerDumpable(this)
         statusBarStateController.addCallback(this)
         keyguardUpdateMonitor.registerCallback(this)
         updateListeningState()
@@ -65,6 +70,13 @@
         updateListeningState()
     }
 
+    override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+        pw.println("KeyguardLiftController:")
+        pw.println("  pickupSensor: $pickupSensor")
+        pw.println("  isListening: $isListening")
+        pw.println("  bouncerVisible: $bouncerVisible")
+    }
+
     private fun updateListeningState() {
         if (pickupSensor == null) {
             return
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 6ee031a..b24942a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -46,6 +46,7 @@
 import com.android.systemui.R;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.qs.QSPanel;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
@@ -329,7 +330,8 @@
         mMultiUserSwitch.setUserSwitcherController(mUserSwitcherController);
         userInfoController.reloadUserInfo();
         Dependency.get(ConfigurationController.class).addCallback(this);
-        mIconManager = new TintedIconManager(findViewById(R.id.statusIcons));
+        mIconManager = new TintedIconManager(findViewById(R.id.statusIcons),
+                Dependency.get(CommandQueue.class));
         Dependency.get(StatusBarIconController.class).addIconGroup(mIconManager);
         onThemeChanged();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index de660ce..092dd49 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -27,7 +27,6 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.Interpolators;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
@@ -49,6 +48,7 @@
     private final DarkIntensityApplier mApplier;
     private final KeyguardStateController mKeyguardStateController;
     private final StatusBarStateController mStatusBarStateController;
+    private final CommandQueue mCommandQueue;
 
     private boolean mTransitionDeferring;
     private long mTransitionDeferringStartTime;
@@ -70,13 +70,14 @@
 
     private final Context mContext;
 
-    public LightBarTransitionsController(Context context, DarkIntensityApplier applier) {
+    public LightBarTransitionsController(Context context, DarkIntensityApplier applier,
+            CommandQueue commandQueue) {
         mApplier = applier;
         mHandler = new Handler();
         mKeyguardStateController = Dependency.get(KeyguardStateController.class);
         mStatusBarStateController = Dependency.get(StatusBarStateController.class);
-        SysUiServiceProvider.getComponent(context, CommandQueue.class)
-                .addCallback(this);
+        mCommandQueue = commandQueue;
+        mCommandQueue.addCallback(this);
         mStatusBarStateController.addCallback(this);
         mDozeAmount = mStatusBarStateController.getDozeAmount();
         mContext = context;
@@ -84,8 +85,7 @@
     }
 
     public void destroy(Context context) {
-        SysUiServiceProvider.getComponent(context, CommandQueue.class)
-                .removeCallback(this);
+        mCommandQueue.removeCallback(this);
         mStatusBarStateController.removeCallback(this);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java
index fbd8d8a..07e9f94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java
@@ -24,6 +24,8 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 
+import com.android.systemui.broadcast.BroadcastDispatcher;
+
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
@@ -40,6 +42,7 @@
 
     private final Context mContext;
     private final UserManager mUserManager;
+    private final BroadcastDispatcher mBroadcastDispatcher;
     private final LinkedList<UserInfo> mProfiles;
     private boolean mListening;
     private int mCurrentUser;
@@ -47,9 +50,10 @@
     /**
      */
     @Inject
-    public ManagedProfileControllerImpl(Context context) {
+    public ManagedProfileControllerImpl(Context context, BroadcastDispatcher broadcastDispatcher) {
         mContext = context;
         mUserManager = UserManager.get(mContext);
+        mBroadcastDispatcher = broadcastDispatcher;
         mProfiles = new LinkedList<UserInfo>();
     }
 
@@ -129,9 +133,10 @@
             filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
             filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
             filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
-            mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null);
+            mBroadcastDispatcher.registerReceiver(
+                    mReceiver, filter, null /* handler */, UserHandle.ALL);
         } else {
-            mContext.unregisterReceiver(mReceiver);
+            mBroadcastDispatcher.unregisterReceiver(mReceiver);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 7030dfc..816327f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -165,7 +165,7 @@
     private Recents mRecents;
     private Divider mDivider;
     private WindowManager mWindowManager;
-    private CommandQueue mCommandQueue;
+    private final CommandQueue mCommandQueue;
     private long mLastLockToAppLongPress;
 
     private Locale mLocale;
@@ -265,7 +265,8 @@
             NavigationModeController navigationModeController,
             StatusBarStateController statusBarStateController,
             SysUiState sysUiFlagsContainer,
-            BroadcastDispatcher broadcastDispatcher) {
+            BroadcastDispatcher broadcastDispatcher,
+            CommandQueue commandQueue) {
         mAccessibilityManagerWrapper = accessibilityManagerWrapper;
         mDeviceProvisionedController = deviceProvisionedController;
         mStatusBarStateController = statusBarStateController;
@@ -277,6 +278,7 @@
         mNavigationModeController = navigationModeController;
         mNavBarMode = navigationModeController.addListener(this);
         mBroadcastDispatcher = broadcastDispatcher;
+        mCommandQueue = commandQueue;
     }
 
     // ----- Fragment Lifecycle Callbacks -----
@@ -284,7 +286,6 @@
     @Override
     public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mCommandQueue = SysUiServiceProvider.getComponent(getContext(), CommandQueue.class);
         mCommandQueue.observe(getLifecycle(), this);
         mStatusBar = SysUiServiceProvider.getComponent(getContext(), StatusBar.class);
         mRecents = SysUiServiceProvider.getComponent(getContext(), Recents.class);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index 3b59031..1a6d3d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -34,6 +34,7 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.CommandQueue;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -78,12 +79,13 @@
         }
     };
 
-    public NavigationBarTransitions(NavigationBarView view) {
+    public NavigationBarTransitions(NavigationBarView view, CommandQueue commandQueue) {
         super(view, R.drawable.nav_background);
         mView = view;
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
-        mLightTransitionsController = new LightBarTransitionsController(view.getContext(), this);
+        mLightTransitionsController = new LightBarTransitionsController(
+                view.getContext(), this, commandQueue);
         mAllowAutoDimWallpaperNotVisible = view.getContext().getResources()
                 .getBoolean(R.bool.config_navigation_bar_enable_auto_dim_no_visible_wallpaper);
         mDarkIntensityListeners = new ArrayList();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 4b4a35b..159a829 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -76,6 +76,7 @@
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NavigationBarController;
 import com.android.systemui.statusbar.policy.DeadZone;
 import com.android.systemui.statusbar.policy.KeyButtonDrawable;
@@ -300,7 +301,7 @@
         mConfiguration.updateFrom(context.getResources().getConfiguration());
 
         mScreenPinningNotify = new ScreenPinningNotify(mContext);
-        mBarTransitions = new NavigationBarTransitions(this);
+        mBarTransitions = new NavigationBarTransitions(this, Dependency.get(CommandQueue.class));
 
         mButtonDispatchers.put(R.id.back, backButton);
         mButtonDispatchers.put(R.id.home, new ButtonDispatcher(R.id.home));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
index 4f7af580..abceb11 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
@@ -31,13 +31,13 @@
 import com.android.systemui.R;
 
 public class NavigationHandle extends View implements ButtonInterface {
-    private float mDarkIntensity = -1;
 
     private final Paint mPaint = new Paint();
     private @ColorInt final int mLightColor;
     private @ColorInt final int mDarkColor;
     private final int mRadius;
     private final int mBottom;
+    private boolean mRequiresInvalidate;
 
     public NavigationHandle(Context context) {
         this(context, null);
@@ -60,6 +60,15 @@
     }
 
     @Override
+    public void setAlpha(float alpha) {
+        super.setAlpha(alpha);
+        if (alpha > 0f && mRequiresInvalidate) {
+            mRequiresInvalidate = false;
+            invalidate();
+        }
+    }
+
+    @Override
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
 
@@ -85,11 +94,15 @@
 
     @Override
     public void setDarkIntensity(float intensity) {
-        if (mDarkIntensity != intensity) {
-            mPaint.setColor((int) ArgbEvaluator.getInstance().evaluate(intensity, mLightColor,
-                    mDarkColor));
-            mDarkIntensity = intensity;
-            invalidate();
+        int color = (int) ArgbEvaluator.getInstance().evaluate(intensity, mLightColor, mDarkColor);
+        if (mPaint.getColor() != color) {
+            mPaint.setColor(color);
+            if (getVisibility() == VISIBLE && getAlpha() > 0) {
+                invalidate();
+            } else {
+                // If we are currently invisible, then invalidate when we are next made visible
+                mRequiresInvalidate = true;
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 30fe68a..6839fb4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static com.android.systemui.SysUiServiceProvider.getComponent;
 import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
 import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
 import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
@@ -55,7 +54,6 @@
 import android.view.WindowInsets;
 import android.view.accessibility.AccessibilityManager;
 import android.widget.FrameLayout;
-import android.widget.LinearLayout;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
@@ -110,6 +108,7 @@
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.util.InjectionInflationController;
+import com.android.systemui.util.Utils;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -243,7 +242,7 @@
     private View mQsNavbarScrim;
     protected NotificationsQuickSettingsContainer mNotificationContainerParent;
     protected NotificationStackScrollLayout mNotificationStackScroller;
-    protected LinearLayout mHomeControlsLayout;
+    protected FrameLayout mHomeControlsLayout;
     private boolean mAnimateNextPositionUpdate;
 
     private int mTrackingPointer;
@@ -463,7 +462,7 @@
             NotificationEntryManager notificationEntryManager,
             KeyguardStateController keyguardStateController,
             StatusBarStateController statusBarStateController, DozeLog dozeLog,
-            DozeParameters dozeParameters) {
+            DozeParameters dozeParameters, CommandQueue commandQueue) {
         super(context, attrs, falsingManager, dozeLog, keyguardStateController,
                 (SysuiStatusBarStateController) statusBarStateController);
         setWillNotDraw(!DEBUG);
@@ -475,7 +474,7 @@
         setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
         mAlphaPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
         setPanelAlpha(255, false /* animate */);
-        mCommandQueue = getComponent(context, CommandQueue.class);
+        mCommandQueue = commandQueue;
         mDisplayId = context.getDisplayId();
         mPulseExpansionHandler = pulseExpansionHandler;
         mDozeParameters = dozeParameters;
@@ -770,8 +769,7 @@
         int sideMargin = res.getDimensionPixelOffset(R.dimen.notification_side_paddings);
         int topMargin =
                 res.getDimensionPixelOffset(com.android.internal.R.dimen.quick_qs_total_height);
-        int flag = Settings.System.getInt(mContext.getContentResolver(), "qs_media_player", 0);
-        if (flag == 1) {
+        if (Utils.useQsMediaPlayer(mContext)) {
             topMargin = res.getDimensionPixelOffset(
                     com.android.internal.R.dimen.quick_qs_total_height_with_media);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 294111c..01cd2b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -40,8 +40,8 @@
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.UiOffloadThread;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.privacy.PrivacyItem;
 import com.android.systemui.privacy.PrivacyItemController;
 import com.android.systemui.privacy.PrivacyItemControllerKt;
@@ -138,7 +138,8 @@
     private BluetoothController mBluetooth;
     private AlarmManager.AlarmClockInfo mNextAlarm;
 
-    public PhoneStatusBarPolicy(Context context, StatusBarIconController iconController) {
+    public PhoneStatusBarPolicy(Context context, StatusBarIconController iconController,
+            CommandQueue commandQueue, BroadcastDispatcher broadcastDispatcher) {
         mContext = context;
         mIconController = iconController;
         mCast = Dependency.get(CastController.class);
@@ -184,7 +185,7 @@
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
-        mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
+        broadcastDispatcher.registerReceiver(mIntentReceiver, filter, mHandler);
 
         // listen for user / profile change.
         try {
@@ -261,7 +262,7 @@
         mSensorPrivacyController.addCallback(mSensorPrivacyListener);
         mLocationController.addCallback(this);
 
-        SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallback(this);
+        commandQueue.addCallback(this);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 53e1467..312ca26 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -19,7 +19,6 @@
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 
 import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
-import static com.android.systemui.SysUiServiceProvider.getComponent;
 
 import android.annotation.Nullable;
 import android.content.Context;
@@ -95,7 +94,7 @@
         super(context, attrs);
 
         mBarTransitions = new PhoneStatusBarTransitions(this);
-        mCommandQueue = getComponent(context, CommandQueue.class);
+        mCommandQueue = Dependency.get(CommandQueue.class);
     }
 
     public BarTransitions getBarTransitions() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 6064fbe..f21a9a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -60,11 +60,13 @@
 import java.util.function.Consumer;
 
 import javax.inject.Inject;
+import javax.inject.Singleton;
 
 /**
  * Controls both the scrim behind the notifications and in front of the notifications (when a
  * security method gets shown).
  */
+@Singleton
 public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnColorsChangedListener,
         Dumpable {
 
@@ -748,6 +750,11 @@
     }
 
     private void onFinished(Callback callback) {
+        if (mPendingFrameCallback != null) {
+            // No animations can finish while we're waiting on the blanking to finish
+            return;
+
+        }
         if (isAnimating(mScrimBehind)
             || isAnimating(mScrimInFront)
             || isAnimating(mScrimForBubble)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index e0597159..13055ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -39,15 +39,20 @@
         @Override
         public void prepare(ScrimState previousState) {
             mFrontTint = Color.BLACK;
-            mBehindTint = previousState.mBehindTint;
+            mBehindTint = Color.BLACK;
             mBubbleTint = previousState.mBubbleTint;
 
             mFrontAlpha = 1f;
-            mBehindAlpha = previousState.mBehindAlpha;
+            mBehindAlpha = 1f;
             mBubbleAlpha = previousState.mBubbleAlpha;
 
             mAnimationDuration = ScrimController.ANIMATION_DURATION_LONG;
         }
+
+        @Override
+        public boolean isLowPowerState() {
+            return true;
+        }
     },
 
     /**
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 2963c94..4148a73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -50,7 +50,6 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
@@ -101,6 +100,7 @@
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
 import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
@@ -157,10 +157,9 @@
 import com.android.systemui.charging.WirelessChargingAnimation;
 import com.android.systemui.classifier.FalsingLog;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.doze.DozeEvent;
+import com.android.systemui.dagger.SystemUIBinder;
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
-import com.android.systemui.doze.DozeReceiver;
 import com.android.systemui.fragments.ExtensionFragmentListener;
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.keyguard.KeyguardSliceProvider;
@@ -170,7 +169,9 @@
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.OverlayPlugin;
 import com.android.systemui.plugins.PluginDependencyProvider;
+import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -178,6 +179,7 @@
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.ScreenPinningRequest;
+import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.shared.system.WindowManagerWrapper;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.stackdivider.WindowManagerProxy;
@@ -236,6 +238,7 @@
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
+import com.android.systemui.statusbar.policy.RemoteInputUriController;
 import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -249,14 +252,11 @@
 import java.util.ArrayList;
 import java.util.Map;
 
-import javax.inject.Inject;
 import javax.inject.Named;
-import javax.inject.Singleton;
 
 import dagger.Lazy;
 import dagger.Subcomponent;
 
-@Singleton
 public class StatusBar extends SystemUI implements DemoMode,
         ActivityStarter, KeyguardStateController.Callback,
         OnHeadsUpChangedListener, CommandQueue.Callbacks, ZenModeController.Callback,
@@ -347,7 +347,7 @@
     /**
      * The {@link StatusBarState} of the status bar.
      */
-    protected int mState;
+    protected int mState; // TODO: remove this. Just use StatusBarStateController
     protected boolean mBouncerShowing;
 
     private PhoneStatusBarPolicy mIconPolicy;
@@ -356,11 +356,13 @@
     private VolumeComponent mVolumeComponent;
     private BrightnessMirrorController mBrightnessMirrorController;
     private boolean mBrightnessMirrorVisible;
-    protected BiometricUnlockController mBiometricUnlockController;
+    private BiometricUnlockController mBiometricUnlockController;
     private final LightBarController mLightBarController;
     private final Lazy<LockscreenWallpaper> mLockscreenWallpaperLazy;
     protected LockscreenWallpaper mLockscreenWallpaper;
     private final AutoHideController mAutoHideController;
+    @Nullable
+    private final KeyguardLiftController mKeyguardLiftController;
 
     private int mNaturalBarHeight = -1;
 
@@ -373,7 +375,7 @@
     protected StatusBarWindowController mStatusBarWindowController;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @VisibleForTesting
-    DozeServiceHost mDozeServiceHost = new DozeServiceHost();
+    DozeServiceHost mDozeServiceHost;
     private boolean mWakeUpComingFromTouch;
     private PointF mWakeUpTouchLocation;
 
@@ -398,6 +400,9 @@
     private final StatusBarWindowViewController.Builder mStatusBarWindowViewControllerBuilder;
     private final NotifLog mNotifLog;
     private final DozeParameters mDozeParameters;
+    private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
+    private final PluginManager mPluginManager;
+    private final RemoteInputUriController mRemoteInputUriController;
 
     // expanded notifications
     protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
@@ -492,7 +497,6 @@
     private final UiOffloadThread mUiOffloadThread;
 
     protected boolean mDozing;
-    private boolean mDozingRequested;
 
     private final NotificationMediaManager mMediaManager;
     private final NotificationLockscreenUserManager mLockscreenUserManager;
@@ -611,7 +615,6 @@
     private ActivityLaunchAnimator mActivityLaunchAnimator;
     protected StatusBarNotificationPresenter mPresenter;
     private NotificationActivityStarter mNotificationActivityStarter;
-    private boolean mPulsing;
     private final BubbleController mBubbleController;
     private final BubbleController.BubbleExpandListener mBubbleExpandListener;
 
@@ -621,7 +624,6 @@
     public void onActiveStateChanged(int code, int uid, String packageName, boolean active) {
         Dependency.get(MAIN_HANDLER).post(() -> {
             mForegroundServiceController.onAppOpChanged(code, uid, packageName, active);
-            mNotificationListController.updateNotificationsForAppOp(code, uid, packageName, active);
         });
     }
 
@@ -631,7 +633,12 @@
             AppOpsManager.OP_COARSE_LOCATION,
             AppOpsManager.OP_FINE_LOCATION};
 
-    @Inject
+    /**
+     * Public constructor for StatusBar.
+     *
+     * StatusBar is considered optional, and therefore can not be marked as @Inject directly.
+     * Instead, an @Provide method is included in {@link SystemUIBinder}.
+     */
     public StatusBar(
             Context context,
             FeatureFlags featureFlags,
@@ -691,7 +698,15 @@
             NotifLog notifLog,
             DozeParameters dozeParameters,
             ScrimController scrimController,
-            Lazy<LockscreenWallpaper> lockscreenWallpaperLazy) {
+            @Nullable KeyguardLiftController keyguardLiftController,
+            Lazy<LockscreenWallpaper> lockscreenWallpaperLazy,
+            Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
+            DozeServiceHost dozeServiceHost,
+            PowerManager powerManager,
+            DozeScrimController dozeScrimController,
+            CommandQueue commandQueue,
+            PluginManager pluginManager,
+            RemoteInputUriController remoteInputUriController) {
         super(context);
         mFeatureFlags = featureFlags;
         mLightBarController = lightBarController;
@@ -748,10 +763,17 @@
         mStatusBarWindowController = statusBarWindowController;
         mStatusBarWindowViewControllerBuilder = statusBarWindowViewControllerBuilder;
         mNotifLog = notifLog;
+        mDozeServiceHost = dozeServiceHost;
+        mPowerManager = powerManager;
         mDozeParameters = dozeParameters;
         mScrimController = scrimController;
+        mKeyguardLiftController = keyguardLiftController;
         mLockscreenWallpaperLazy = lockscreenWallpaperLazy;
-
+        mDozeScrimController = dozeScrimController;
+        mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
+        mCommandQueue = commandQueue;
+        mPluginManager = pluginManager;
+        mRemoteInputUriController = remoteInputUriController;
         mBubbleExpandListener =
                 (isExpanding, key) -> {
                     mEntryManager.updateNotifications("onBubbleExpandChanged");
@@ -802,7 +824,6 @@
         mAccessibilityManager = (AccessibilityManager)
                 mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
 
-        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController);
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
@@ -812,7 +833,6 @@
         mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
 
         // Connect in to the status bar manager service
-        mCommandQueue = getComponent(CommandQueue.class);
         mCommandQueue.addCallback(this);
 
         RegisterStatusBarResult result = null;
@@ -830,8 +850,8 @@
         if (mWallpaperSupported) {
             // Make sure we always have the most current wallpaper info.
             IntentFilter wallpaperChangedFilter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
-            mContext.registerReceiverAsUser(mWallpaperChangedReceiver, UserHandle.ALL,
-                    wallpaperChangedFilter, null /* broadcastPermission */, null /* scheduler */);
+            mBroadcastDispatcher.registerReceiver(mWallpaperChangedReceiver, wallpaperChangedFilter,
+                    null /* handler */, UserHandle.ALL);
             mWallpaperChangedReceiver.onReceive(mContext, null);
         } else if (DEBUG) {
             Log.v(TAG, "start(): no wallpaper service ");
@@ -895,13 +915,17 @@
         // end old BaseStatusBar.start().
 
         // Lastly, call to the icon policy to install/update all the icons.
-        mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController);
+        mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController, mCommandQueue,
+                mBroadcastDispatcher);
         mSignalPolicy = new StatusBarSignalPolicy(mContext, mIconController);
 
         mKeyguardStateController.addCallback(this);
         startKeyguard();
 
         mKeyguardUpdateMonitor.registerCallback(mUpdateCallback);
+        mDozeServiceHost.initialize(this, mNotificationIconAreaController,
+                mStatusBarWindowViewController, mStatusBarWindow, mStatusBarKeyguardViewManager,
+                mNotificationPanel, mAmbientIndicationContainer);
         putComponent(DozeHost.class, mDozeServiceHost);
 
         mScreenPinningRequest = new ScreenPinningRequest(mContext);
@@ -916,6 +940,50 @@
         int disabledFlags2 = result.mDisabledFlags2;
         Dependency.get(InitController.class).addPostInitTask(
                 () -> setUpDisableFlags(disabledFlags1, disabledFlags2));
+
+        mPluginManager.addPluginListener(
+                new PluginListener<OverlayPlugin>() {
+                    private ArraySet<OverlayPlugin> mOverlays = new ArraySet<>();
+
+                    @Override
+                    public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
+                        mMainThreadHandler.post(
+                                () -> plugin.setup(getStatusBarWindow(), getNavigationBarView(),
+                                        new Callback(plugin), mDozeParameters));
+                    }
+
+                    @Override
+                    public void onPluginDisconnected(OverlayPlugin plugin) {
+                        mMainThreadHandler.post(() -> {
+                            mOverlays.remove(plugin);
+                            mStatusBarWindowController.setForcePluginOpen(mOverlays.size() != 0);
+                        });
+                    }
+
+                    class Callback implements OverlayPlugin.Callback {
+                        private final OverlayPlugin mPlugin;
+
+                        Callback(OverlayPlugin plugin) {
+                            mPlugin = plugin;
+                        }
+
+                        @Override
+                        public void onHoldStatusBarOpenChange() {
+                            if (mPlugin.holdStatusBarOpen()) {
+                                mOverlays.add(mPlugin);
+                            } else {
+                                mOverlays.remove(mPlugin);
+                            }
+                            mMainThreadHandler.post(() -> {
+                                mStatusBarWindowController
+                                        .setStateListener(b -> mOverlays.forEach(
+                                                o -> o.setCollapseDesired(b)));
+                                mStatusBarWindowController
+                                        .setForcePluginOpen(mOverlays.size() != 0);
+                            });
+                        }
+                    }
+                }, OverlayPlugin.class, true /* Allow multiple plugins */);
     }
 
     // ================================================================================
@@ -994,7 +1062,7 @@
                     mHeadsUpAppearanceController = new HeadsUpAppearanceController(
                             mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow,
                             mStatusBarStateController, mKeyguardBypassController,
-                            mKeyguardStateController, mWakeUpCoordinator);
+                            mKeyguardStateController, mWakeUpCoordinator, mCommandQueue);
                     mHeadsUpAppearanceController.readFrom(oldController);
                     mStatusBarWindowViewController.setStatusBarView(mStatusBarView);
                     updateAreThereNotifications();
@@ -1066,7 +1134,6 @@
 
         mNotificationPanel.initDependencies(this, mGroupManager, mNotificationShelf,
                 mHeadsUpManager, mNotificationIconAreaController, mScrimController);
-        mDozeScrimController = new DozeScrimController(mDozeParameters, mDozeLog);
 
         BackDropView backdrop = mStatusBarWindow.findViewById(R.id.backdrop);
         mMediaManager.setup(backdrop, backdrop.findViewById(R.id.backdrop_front),
@@ -1201,7 +1268,7 @@
         mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanel,
                 mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController,
                 mScrimController, mActivityLaunchAnimator, mDynamicPrivacyController,
-                mNotificationAlertingManager, rowBinder, mKeyguardStateController);
+                mNotificationAlertingManager, rowBinder, mKeyguardStateController, mCommandQueue);
 
         mNotificationListController =
                 new NotificationListController(
@@ -1232,6 +1299,8 @@
         mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
 
         mEntryManager.setRowBinder(rowBinder);
+        mRemoteInputUriController.attach(mEntryManager);
+
         rowBinder.setNotificationClicker(new NotificationClicker(
                 this, mBubbleController, mNotificationActivityStarter));
 
@@ -1370,11 +1439,7 @@
 
     protected void startKeyguard() {
         Trace.beginSection("StatusBar#startKeyguard");
-        mBiometricUnlockController = new BiometricUnlockController(mContext,
-                mDozeScrimController, mKeyguardViewMediator,
-                mScrimController, this, mKeyguardStateController, new Handler(),
-                mKeyguardUpdateMonitor, mKeyguardBypassController, mDozeParameters);
-        putComponent(BiometricUnlockController.class, mBiometricUnlockController);
+        mBiometricUnlockController = mBiometricUnlockControllerLazy.get();
         mStatusBarKeyguardViewManager = mKeyguardViewMediator.registerStatusBar(this,
                 getBouncerContainer(), mNotificationPanel, mBiometricUnlockController,
                 mStatusBarWindow.findViewById(R.id.lock_icon_container), mStackScroller,
@@ -1528,7 +1593,6 @@
                         .start();
             }
         }
-        mMediaManager.findAndUpdateMediaNotifications();
     }
 
     private void updateReportRejectedTouchVisibility() {
@@ -1731,7 +1795,7 @@
         if (isDozing() && isHeadsUp) {
             entry.setPulseSuppressed(false);
             mDozeServiceHost.fireNotificationPulse(entry);
-            if (mPulsing) {
+            if (mDozeServiceHost.isPulsing()) {
                 mDozeScrimController.cancelPendingPulseTimeout();
             }
         }
@@ -1763,7 +1827,7 @@
     }
 
     public boolean isPulsing() {
-        return mPulsing;
+        return mDozeServiceHost.isPulsing();
     }
 
     public boolean hideStatusBarIconsWhenExpanded() {
@@ -2516,10 +2580,6 @@
 
         mDozeLog.dump(pw);
 
-        if (mBiometricUnlockController != null) {
-            mBiometricUnlockController.dump(pw);
-        }
-
         if (mKeyguardIndicationController != null) {
             mKeyguardIndicationController.dump(fd, pw, args);
         }
@@ -2573,14 +2633,6 @@
             mLightBarController.dump(fd, pw, args);
         }
 
-        if (mKeyguardBypassController != null) {
-            mKeyguardBypassController.dump(pw);
-        }
-
-        if (mKeyguardUpdateMonitor != null) {
-            mKeyguardUpdateMonitor.dump(fd, pw, args);
-        }
-
         mFalsingManager.dump(pw);
         FalsingLog.dump(pw);
 
@@ -2826,7 +2878,7 @@
         if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_ASLEEP
                 && mKeyguardStateController.canDismissLockScreen()
                 && !mStatusBarStateController.leaveOpenOnKeyguardHide()
-                && isPulsing()) {
+                && mDozeServiceHost.isPulsing()) {
             // Reuse the biometric wake-and-unlock transition if we dismiss keyguard from a pulse.
             // TODO: Factor this transition out of BiometricUnlockController.
             mBiometricUnlockController.startWakeAndUnlock(
@@ -3157,7 +3209,7 @@
         return mState == StatusBarState.FULLSCREEN_USER_SWITCHER;
     }
 
-    private boolean updateIsKeyguard() {
+    boolean updateIsKeyguard() {
         boolean wakeAndUnlocking = mBiometricUnlockController.getMode()
                 == BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
 
@@ -3165,8 +3217,8 @@
         // there's no surface we can show to the user. Note that the device goes fully interactive
         // late in the transition, so we also allow the device to start dozing once the screen has
         // turned off fully.
-        boolean keyguardForDozing = mDozingRequested &&
-                (!mDeviceInteractive || isGoingToSleep() && (isScreenFullyOff() || mIsKeyguard));
+        boolean keyguardForDozing = mDozeServiceHost.getDozingRequested()
+                && (!mDeviceInteractive || isGoingToSleep() && (isScreenFullyOff() || mIsKeyguard));
         boolean shouldBeKeyguard = (mStatusBarStateController.isKeyguardRequested()
                 || keyguardForDozing) && !wakeAndUnlocking;
         if (keyguardForDozing) {
@@ -3582,7 +3634,7 @@
     public void onStateChanged(int newState) {
         mState = newState;
         updateReportRejectedTouchVisibility();
-        updateDozing();
+        mDozeServiceHost.updateDozing();
         updateTheme();
         mNavigationBarController.touchAutoDim(mDisplayId);
         Trace.beginSection("StatusBar#updateKeyguardState");
@@ -3620,9 +3672,11 @@
     public void onDozingChanged(boolean isDozing) {
         Trace.beginSection("StatusBar#updateDozing");
         mDozing = isDozing;
+        mDozeServiceHost.setDozing(mDozing);
 
         // Collapse the notification panel if open
-        boolean dozingAnimated = mDozingRequested && mDozeParameters.shouldControlScreenOff();
+        boolean dozingAnimated = mDozeServiceHost.getDozingRequested()
+                && mDozeParameters.shouldControlScreenOff();
         mNotificationPanel.resetViews(dozingAnimated);
 
         updateQsExpansionEnabled();
@@ -3630,26 +3684,12 @@
 
         mEntryManager.updateNotifications("onDozingChanged");
         updateDozingState();
+        mDozeServiceHost.updateDozing();
         updateScrimController();
         updateReportRejectedTouchVisibility();
         Trace.endSection();
     }
 
-    private void updateDozing() {
-        // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked.
-        boolean dozing = mDozingRequested && mState == StatusBarState.KEYGUARD
-                || mBiometricUnlockController.getMode()
-                == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
-        // When in wake-and-unlock we may not have received a change to mState
-        // but we still should not be dozing, manually set to false.
-        if (mBiometricUnlockController.getMode() ==
-                BiometricUnlockController.MODE_WAKE_AND_UNLOCK) {
-            dozing = false;
-        }
-
-        mStatusBarStateController.setIsDozing(dozing);
-    }
-
     private void updateKeyguardState() {
         mKeyguardStateController.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
                 mStatusBarKeyguardViewManager.isOccluded());
@@ -3874,10 +3914,11 @@
      * collapse the panel after we expanded it, and thus we would end up with a blank
      * Keyguard.
      */
-    private void updateNotificationPanelTouchState() {
+    void updateNotificationPanelTouchState() {
         boolean goingToSleepWithoutAnimation = isGoingToSleep()
                 && !mDozeParameters.shouldControlScreenOff();
-        boolean disabled = (!mDeviceInteractive && !mPulsing) || goingToSleepWithoutAnimation;
+        boolean disabled = (!mDeviceInteractive && !mDozeServiceHost.isPulsing())
+                || goingToSleepWithoutAnimation;
         mNotificationPanel.setTouchAndAnimationDisabled(disabled);
         mNotificationIconAreaController.setAnimationsEnabled(!disabled);
     }
@@ -4027,7 +4068,7 @@
     }
 
     public void notifyBiometricAuthModeChanged() {
-        updateDozing();
+        mDozeServiceHost.updateDozing();
         updateScrimController();
         mStatusBarWindowViewController.onBiometricAuthModeChanged(
                 mBiometricUnlockController.isWakeAndUnlock(),
@@ -4063,7 +4104,7 @@
             mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
         } else if (mBrightnessMirrorVisible) {
             mScrimController.transitionTo(ScrimState.BRIGHTNESS_MIRROR);
-        } else if (isPulsing()) {
+        } else if (mDozeServiceHost.isPulsing()) {
             mScrimController.transitionTo(ScrimState.PULSING,
                     mDozeScrimController.getScrimCallback());
         } else if (mDozeServiceHost.hasPendingScreenOffCallback()) {
@@ -4093,292 +4134,13 @@
         return mStatusBarKeyguardViewManager.isShowing();
     }
 
-    @VisibleForTesting
-    final class DozeServiceHost implements DozeHost {
-        private final ArrayList<Callback> mCallbacks = new ArrayList<>();
-        private boolean mAnimateWakeup;
-        private boolean mAnimateScreenOff;
-        private boolean mIgnoreTouchWhilePulsing;
-        private Runnable mPendingScreenOffCallback;
-        @VisibleForTesting
-        boolean mWakeLockScreenPerformsAuth = SystemProperties.getBoolean(
-                "persist.sysui.wake_performs_auth", true);
-
-        @Override
-        public String toString() {
-            return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]";
-        }
-
-        public void firePowerSaveChanged(boolean active) {
-            for (Callback callback : mCallbacks) {
-                callback.onPowerSaveChanged(active);
-            }
-        }
-
-        public void fireNotificationPulse(NotificationEntry entry) {
-            Runnable pulseSupressedListener = () -> {
-                entry.setPulseSuppressed(true);
-                mNotificationIconAreaController.updateAodNotificationIcons();
-            };
-            for (Callback callback : mCallbacks) {
-                callback.onNotificationAlerted(pulseSupressedListener);
-            }
-        }
-
-        @Override
-        public void addCallback(@NonNull Callback callback) {
-            mCallbacks.add(callback);
-        }
-
-        @Override
-        public void removeCallback(@NonNull Callback callback) {
-            mCallbacks.remove(callback);
-        }
-
-        @Override
-        public void startDozing() {
-            if (!mDozingRequested) {
-                mDozingRequested = true;
-                mDozeLog.traceDozing(mDozing);
-                updateDozing();
-                updateIsKeyguard();
-            }
-        }
-
-        @Override
-        public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) {
-            if (reason == DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS) {
-                mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
-                        "com.android.systemui:LONG_PRESS");
-                startAssist(new Bundle());
-                return;
-            }
-
-            if (reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
-                mScrimController.setWakeLockScreenSensorActive(true);
-            }
-
-            if (reason == DozeEvent.PULSE_REASON_DOCKING && mStatusBarWindow != null) {
-                mStatusBarWindowViewController.suppressWakeUpGesture(true);
-            }
-
-            boolean passiveAuthInterrupt = reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN
-                            && mWakeLockScreenPerformsAuth;
-            // Set the state to pulsing, so ScrimController will know what to do once we ask it to
-            // execute the transition. The pulse callback will then be invoked when the scrims
-            // are black, indicating that StatusBar is ready to present the rest of the UI.
-            mPulsing = true;
-            mDozeScrimController.pulse(new PulseCallback() {
-                @Override
-                public void onPulseStarted() {
-                    callback.onPulseStarted();
-                    updateNotificationPanelTouchState();
-                    setPulsing(true);
-                }
-
-                @Override
-                public void onPulseFinished() {
-                    mPulsing = false;
-                    callback.onPulseFinished();
-                    updateNotificationPanelTouchState();
-                    mScrimController.setWakeLockScreenSensorActive(false);
-                    if (mStatusBarWindow != null) {
-                        mStatusBarWindowViewController.suppressWakeUpGesture(false);
-                    }
-                    setPulsing(false);
-                }
-
-                private void setPulsing(boolean pulsing) {
-                    mStatusBarStateController.setPulsing(pulsing);
-                    mStatusBarKeyguardViewManager.setPulsing(pulsing);
-                    mKeyguardViewMediator.setPulsing(pulsing);
-                    mNotificationPanel.setPulsing(pulsing);
-                    mVisualStabilityManager.setPulsing(pulsing);
-                    mStatusBarWindowViewController.setPulsing(pulsing);
-                    mIgnoreTouchWhilePulsing = false;
-                    if (mKeyguardUpdateMonitor != null && passiveAuthInterrupt) {
-                        mKeyguardUpdateMonitor.onAuthInterruptDetected(pulsing /* active */);
-                    }
-                    updateScrimController();
-                    mPulseExpansionHandler.setPulsing(pulsing);
-                    mWakeUpCoordinator.setPulsing(pulsing);
-                }
-            }, reason);
-            // DozeScrimController is in pulse state, now let's ask ScrimController to start
-            // pulsing and draw the black frame, if necessary.
-            updateScrimController();
-        }
-
-        @Override
-        public void stopDozing() {
-            if (mDozingRequested) {
-                mDozingRequested = false;
-                mDozeLog.traceDozing(mDozing);
-                updateDozing();
-            }
-        }
-
-        @Override
-        public void onIgnoreTouchWhilePulsing(boolean ignore) {
-            if (ignore != mIgnoreTouchWhilePulsing) {
-                mDozeLog.tracePulseTouchDisabledByProx(ignore);
-            }
-            mIgnoreTouchWhilePulsing = ignore;
-            if (isDozing() && ignore) {
-                mStatusBarWindowViewController.cancelCurrentTouch();
-            }
-        }
-
-        @Override
-        public void dozeTimeTick() {
-            mNotificationPanel.dozeTimeTick();
-            if (mAmbientIndicationContainer instanceof DozeReceiver) {
-                ((DozeReceiver) mAmbientIndicationContainer).dozeTimeTick();
-            }
-        }
-
-        @Override
-        public boolean isPowerSaveActive() {
-            return mBatteryController.isAodPowerSave();
-        }
-
-        @Override
-        public boolean isPulsingBlocked() {
-            return mBiometricUnlockController.getMode()
-                    == BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
-        }
-
-        @Override
-        public boolean isProvisioned() {
-            return mDeviceProvisionedController.isDeviceProvisioned()
-                    && mDeviceProvisionedController.isCurrentUserSetup();
-        }
-
-        @Override
-        public boolean isBlockingDoze() {
-            if (mBiometricUnlockController.hasPendingAuthentication()) {
-                Log.i(TAG, "Blocking AOD because fingerprint has authenticated");
-                return true;
-            }
-            return false;
-        }
-
-        @Override
-        public void extendPulse(int reason) {
-            if (reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
-                mScrimController.setWakeLockScreenSensorActive(true);
-            }
-            if (mDozeScrimController.isPulsing() && mHeadsUpManager.hasNotifications()) {
-                mHeadsUpManager.extendHeadsUp();
-            } else {
-                mDozeScrimController.extendPulse();
-            }
-        }
-
-        @Override
-        public void stopPulsing() {
-            if (mDozeScrimController.isPulsing()) {
-                mDozeScrimController.pulseOutNow();
-            }
-        }
-
-        @Override
-        public void setAnimateWakeup(boolean animateWakeup) {
-            if (mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_AWAKE
-                    || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_WAKING) {
-                // Too late to change the wakeup animation.
-                return;
-            }
-            mAnimateWakeup = animateWakeup;
-        }
-
-        @Override
-        public void setAnimateScreenOff(boolean animateScreenOff) {
-            mAnimateScreenOff = animateScreenOff;
-        }
-
-        @Override
-        public void onSlpiTap(float screenX, float screenY) {
-            if (screenX > 0 && screenY > 0 && mAmbientIndicationContainer != null
-                && mAmbientIndicationContainer.getVisibility() == View.VISIBLE) {
-                mAmbientIndicationContainer.getLocationOnScreen(mTmpInt2);
-                float viewX = screenX - mTmpInt2[0];
-                float viewY = screenY - mTmpInt2[1];
-                if (0 <= viewX && viewX <= mAmbientIndicationContainer.getWidth()
-                        && 0 <= viewY && viewY <= mAmbientIndicationContainer.getHeight()) {
-                    dispatchTap(mAmbientIndicationContainer, viewX, viewY);
-                }
-            }
-        }
-
-        @Override
-        public void setDozeScreenBrightness(int value) {
-            mStatusBarWindowController.setDozeScreenBrightness(value);
-        }
-
-        @Override
-        public void setAodDimmingScrim(float scrimOpacity) {
-            mScrimController.setAodFrontScrimAlpha(scrimOpacity);
-        }
-
-        @Override
-        public void prepareForGentleSleep(Runnable onDisplayOffCallback) {
-            if (onDisplayOffCallback != null) {
-                Log.w(TAG, "Overlapping onDisplayOffCallback. Ignoring previous one.");
-            }
-            mPendingScreenOffCallback = onDisplayOffCallback;
-            updateScrimController();
-        }
-
-        /**
-         * When the dozing host is waiting for scrims to fade out to change the display state.
-         */
-        boolean hasPendingScreenOffCallback() {
-            return mPendingScreenOffCallback != null;
-        }
-
-        /**
-         * Executes an nullifies the pending display state callback.
-         *
-         * @see #hasPendingScreenOffCallback()
-         * @see #prepareForGentleSleep(Runnable)
-         */
-        void executePendingScreenOffCallback() {
-            if (mPendingScreenOffCallback == null) {
-                return;
-            }
-            mPendingScreenOffCallback.run();
-            mPendingScreenOffCallback = null;
-        }
-
-        private void dispatchTap(View view, float x, float y) {
-            long now = SystemClock.elapsedRealtime();
-            dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_DOWN);
-            dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_UP);
-        }
-
-        private void dispatchTouchEvent(View view, float x, float y, long now, int action) {
-            MotionEvent ev = MotionEvent.obtain(now, now, action, x, y, 0 /* meta */);
-            view.dispatchTouchEvent(ev);
-            ev.recycle();
-        }
-
-        private boolean shouldAnimateWakeup() {
-            return mAnimateWakeup;
-        }
-
-        public boolean shouldAnimateScreenOff() {
-            return mAnimateScreenOff;
-        }
-    }
-
     public boolean shouldIgnoreTouch() {
-        return isDozing() && mDozeServiceHost.mIgnoreTouchWhilePulsing;
+        return isDozing() && mDozeServiceHost.getIgnoreTouchWhilePulsing();
     }
 
     // Begin Extra BaseStatusBar methods.
 
-    protected CommandQueue mCommandQueue;
+    protected final CommandQueue mCommandQueue;
     protected IStatusBarService mBarService;
 
     // all notifications
@@ -4400,7 +4162,7 @@
     private boolean mVisibleToUser;
 
     protected DevicePolicyManager mDevicePolicyManager;
-    protected PowerManager mPowerManager;
+    private final PowerManager mPowerManager;
     protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
 
     protected KeyguardManager mKeyguardManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 2e2ff1a..5daef24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -40,6 +40,7 @@
 import com.android.systemui.R;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.StatusBarMobileView;
 import com.android.systemui.statusbar.StatusBarWifiView;
@@ -96,8 +97,8 @@
         private final DarkIconDispatcher mDarkIconDispatcher;
         private int mIconHPadding;
 
-        public DarkIconManager(LinearLayout linearLayout) {
-            super(linearLayout);
+        public DarkIconManager(LinearLayout linearLayout, CommandQueue commandQueue) {
+            super(linearLayout, commandQueue);
             mIconHPadding = mContext.getResources().getDimensionPixelSize(
                     R.dimen.status_bar_icon_padding);
             mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
@@ -156,8 +157,8 @@
     public static class TintedIconManager extends IconManager {
         private int mColor;
 
-        public TintedIconManager(ViewGroup group) {
-            super(group);
+        public TintedIconManager(ViewGroup group, CommandQueue commandQueue) {
+            super(group, commandQueue);
         }
 
         @Override
@@ -203,14 +204,14 @@
         private boolean mIsInDemoMode;
         protected DemoStatusIcons mDemoStatusIcons;
 
-        public IconManager(ViewGroup group) {
+        public IconManager(ViewGroup group, CommandQueue commandQueue) {
             mGroup = group;
             mContext = group.getContext();
             mIconSize = mContext.getResources().getDimensionPixelSize(
                     com.android.internal.R.dimen.status_bar_icon_size);
 
             DisableStateTracker tracker =
-                    new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS);
+                    new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS, commandQueue);
             mGroup.addOnAttachStateChangeListener(tracker);
             if (mGroup.isAttachedToWindow()) {
                 // In case we miss the first onAttachedToWindow event
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index e0b1846..aa062eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -29,7 +29,6 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.StatusIconDisplayable;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
@@ -70,7 +69,7 @@
     private boolean mIsDark = false;
 
     @Inject
-    public StatusBarIconControllerImpl(Context context) {
+    public StatusBarIconControllerImpl(Context context, CommandQueue commandQueue) {
         super(context.getResources().getStringArray(
                 com.android.internal.R.array.config_statusBarIcons));
         Dependency.get(ConfigurationController.class).addCallback(this);
@@ -79,8 +78,7 @@
 
         loadDimens();
 
-        SysUiServiceProvider.getComponent(context, CommandQueue.class)
-                .addCallback(this);
+        commandQueue.addCallback(this);
         Dependency.get(TunerService.class).addTunable(this, ICON_BLACKLIST);
     }
 
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 b01a8d4..02e5ebf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -14,7 +14,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static com.android.systemui.SysUiServiceProvider.getComponent;
 import static com.android.systemui.statusbar.phone.StatusBar.CLOSE_PANEL_WHEN_EMPTIED;
 import static com.android.systemui.statusbar.phone.StatusBar.DEBUG;
 import static com.android.systemui.statusbar.phone.StatusBar.MULTIUSER_DEBUG;
@@ -139,13 +138,14 @@
             DynamicPrivacyController dynamicPrivacyController,
             NotificationAlertingManager notificationAlertingManager,
             NotificationRowBinderImpl notificationRowBinder,
-            KeyguardStateController keyguardStateController) {
+            KeyguardStateController keyguardStateController,
+            CommandQueue commandQueue) {
         mContext = context;
         mKeyguardStateController = keyguardStateController;
         mNotificationPanel = panel;
         mHeadsUpManager = headsUp;
         mDynamicPrivacyController = dynamicPrivacyController;
-        mCommandQueue = getComponent(context, CommandQueue.class);
+        mCommandQueue = commandQueue;
         mAboveShelfObserver = new AboveShelfObserver(stackScroller);
         mActivityLaunchAnimator = activityLaunchAnimator;
         mAboveShelfObserver.setListener(statusBarWindow.findViewById(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 1def89b..b5a7847 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -16,7 +16,6 @@
 
 import static android.content.Intent.ACTION_DEVICE_LOCKED_CHANGED;
 
-import static com.android.systemui.SysUiServiceProvider.getComponent;
 import static com.android.systemui.statusbar.NotificationLockscreenUserManager.NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION;
 
 import android.app.ActivityManager;
@@ -80,7 +79,8 @@
             NotificationLockscreenUserManager notificationLockscreenUserManager,
             KeyguardStateController keyguardStateController,
             StatusBarStateController statusBarStateController,
-            ActivityStarter activityStarter, ShadeController shadeController) {
+            ActivityStarter activityStarter, ShadeController shadeController,
+            CommandQueue commandQueue) {
         mContext = context;
         mContext.registerReceiverAsUser(mChallengeReceiver, UserHandle.ALL,
                 new IntentFilter(ACTION_DEVICE_LOCKED_CHANGED), null, null);
@@ -91,7 +91,7 @@
         mActivityStarter = activityStarter;
         mStatusBarStateController.addCallback(this);
         mKeyguardManager = context.getSystemService(KeyguardManager.class);
-        mCommandQueue = getComponent(context, CommandQueue.class);
+        mCommandQueue = commandQueue;
         mCommandQueue.addCallback(this);
         mActivityIntentHelper = new ActivityIntentHelper(mContext);
         mGroupManager = groupManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
index fd3f9c8..b7ada5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
@@ -39,6 +39,7 @@
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.PulseExpansionHandler;
@@ -94,7 +95,8 @@
             KeyguardStateController keyguardStateController,
             SysuiStatusBarStateController statusBarStateController,
             DozeLog dozeLog,
-            DozeParameters dozeParameters) {
+            DozeParameters dozeParameters,
+            CommandQueue commandQueue) {
         mView = view;
         mFalsingManager = falsingManager;
 
@@ -115,7 +117,8 @@
                 keyguardStateController,
                 statusBarStateController,
                 dozeLog,
-                dozeParameters);
+                dozeParameters,
+                commandQueue);
         ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
         notificationPanelView.setVisibility(View.INVISIBLE);
@@ -488,6 +491,7 @@
         private final NotificationEntryManager mNotificationEntryManager;
         private final DozeLog mDozeLog;
         private final DozeParameters mDozeParameters;
+        private final CommandQueue mCommandQueue;
         private StatusBarWindowView mView;
 
         @Inject
@@ -505,7 +509,8 @@
                 KeyguardStateController keyguardStateController,
                 StatusBarStateController statusBarStateController,
                 DozeLog dozeLog,
-                DozeParameters dozeParameters) {
+                DozeParameters dozeParameters,
+                CommandQueue commandQueue) {
             mInjectionInflationController = injectionInflationController;
             mCoordinator = coordinator;
             mPulseExpansionHandler = pulseExpansionHandler;
@@ -520,6 +525,7 @@
             mStatusBarStateController = (SysuiStatusBarStateController) statusBarStateController;
             mDozeLog = dozeLog;
             mDozeParameters = dozeParameters;
+            mCommandQueue = commandQueue;
         }
 
         /**
@@ -558,7 +564,8 @@
                     mKeyguardStateController,
                     mStatusBarStateController,
                     mDozeLog,
-                    mDozeParameters);
+                    mDozeParameters,
+                    mCommandQueue);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index 3fc9b44..f0f9420 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -34,6 +34,7 @@
 import com.android.settingslib.fuelgauge.Estimate;
 import com.android.settingslib.utils.PowerUtil;
 import com.android.systemui.Dependency;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.power.EnhancedEstimates;
 
 import java.io.FileDescriptor;
@@ -58,6 +59,7 @@
     private static final int UPDATE_GRANULARITY_MSEC = 1000 * 60;
 
     private final EnhancedEstimates mEstimates;
+    private final BroadcastDispatcher mBroadcastDispatcher;
     private final ArrayList<BatteryController.BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>();
     private final ArrayList<EstimateFetchCompletion> mFetchCallbacks = new ArrayList<>();
     private final PowerManager mPowerManager;
@@ -76,17 +78,20 @@
     private boolean mFetchingEstimate = false;
 
     @Inject
-    public BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates) {
-        this(context, enhancedEstimates, context.getSystemService(PowerManager.class));
+    public BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates,
+            BroadcastDispatcher broadcastDispatcher) {
+        this(context, enhancedEstimates, context.getSystemService(PowerManager.class),
+                broadcastDispatcher);
     }
 
     @VisibleForTesting
     BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates,
-            PowerManager powerManager) {
+            PowerManager powerManager, BroadcastDispatcher broadcastDispatcher) {
         mContext = context;
         mHandler = new Handler();
         mPowerManager = powerManager;
         mEstimates = enhancedEstimates;
+        mBroadcastDispatcher = broadcastDispatcher;
 
         registerReceiver();
         updatePowerSave();
@@ -99,7 +104,7 @@
         filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
         filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING);
         filter.addAction(ACTION_LEVEL_TEST);
-        mContext.registerReceiver(this, filter);
+        mBroadcastDispatcher.registerReceiver(this, filter);
     }
 
     @Override
@@ -306,7 +311,7 @@
     public void dispatchDemoCommand(String command, Bundle args) {
         if (!mDemoMode && command.equals(COMMAND_ENTER)) {
             mDemoMode = true;
-            mContext.unregisterReceiver(this);
+            mBroadcastDispatcher.unregisterReceiver(this);
         } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
             mDemoMode = false;
             registerReceiver();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index b331fc3..dba3b92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar.policy;
 
-import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
-
 import android.app.StatusBarManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -45,7 +43,6 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
@@ -63,9 +60,6 @@
 import java.util.Locale;
 import java.util.TimeZone;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-
 /**
  * Digital clock for the status bar.
  */
@@ -81,6 +75,7 @@
     private static final String VISIBILITY = "visibility";
 
     private final CurrentUserTracker mCurrentUserTracker;
+    private final CommandQueue mCommandQueue;
     private int mCurrentUserId;
 
     private boolean mClockVisibleByPolicy = true;
@@ -116,18 +111,12 @@
     private final BroadcastDispatcher mBroadcastDispatcher;
 
     public Clock(Context context, AttributeSet attrs) {
-        this(context, attrs, null);
+        this(context, attrs, 0);
     }
 
-    @Inject
-    public Clock(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
-            BroadcastDispatcher broadcastDispatcher) {
-        this(context, attrs, 0, broadcastDispatcher);
-    }
-
-    public Clock(Context context, AttributeSet attrs, int defStyle,
-            BroadcastDispatcher broadcastDispatcher) {
+    public Clock(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+        mCommandQueue = Dependency.get(CommandQueue.class);
         TypedArray a = context.getTheme().obtainStyledAttributes(
                 attrs,
                 R.styleable.Clock,
@@ -139,13 +128,13 @@
         } finally {
             a.recycle();
         }
-        mCurrentUserTracker = new CurrentUserTracker(context) {
+        mBroadcastDispatcher = Dependency.get(BroadcastDispatcher.class);
+        mCurrentUserTracker = new CurrentUserTracker(mBroadcastDispatcher) {
             @Override
             public void onUserSwitched(int newUserId) {
                 mCurrentUserId = newUserId;
             }
         };
-        mBroadcastDispatcher = broadcastDispatcher;
     }
 
     @Override
@@ -196,11 +185,11 @@
             filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
             filter.addAction(Intent.ACTION_USER_SWITCHED);
 
-            getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter,
-                    null, Dependency.get(Dependency.TIME_TICK_HANDLER));
+            mBroadcastDispatcher.registerReceiver(mIntentReceiver, filter,
+                    Dependency.get(Dependency.TIME_TICK_HANDLER), UserHandle.ALL);
             Dependency.get(TunerService.class).addTunable(this, CLOCK_SECONDS,
                     StatusBarIconController.ICON_BLACKLIST);
-            SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallback(this);
+            mCommandQueue.addCallback(this);
             if (mShowDark) {
                 Dependency.get(DarkIconDispatcher.class).addDarkReceiver(this);
             }
@@ -224,11 +213,10 @@
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         if (mAttached) {
-            getContext().unregisterReceiver(mIntentReceiver);
+            mBroadcastDispatcher.unregisterReceiver(mIntentReceiver);
             mAttached = false;
             Dependency.get(TunerService.class).removeTunable(this);
-            SysUiServiceProvider.getComponent(getContext(), CommandQueue.class)
-                    .removeCallback(this);
+            mCommandQueue.removeCallback(this);
             if (mShowDark) {
                 Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(this);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
index 74a30fa..d488767 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
@@ -29,6 +29,7 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 
 import java.util.Date;
 import java.util.Locale;
@@ -41,6 +42,7 @@
     private DateFormat mDateFormat;
     private String mLastText;
     private String mDatePattern;
+    private final BroadcastDispatcher mBroadcastDispatcher;
 
     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
@@ -75,6 +77,7 @@
         if (mDatePattern == null) {
             mDatePattern = getContext().getString(R.string.system_ui_date_pattern);
         }
+        mBroadcastDispatcher = Dependency.get(BroadcastDispatcher.class);
     }
 
     @Override
@@ -86,7 +89,7 @@
         filter.addAction(Intent.ACTION_TIME_CHANGED);
         filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
         filter.addAction(Intent.ACTION_LOCALE_CHANGED);
-        getContext().registerReceiver(mIntentReceiver, filter, null,
+        mBroadcastDispatcher.registerReceiver(mIntentReceiver, filter,
                 Dependency.get(Dependency.TIME_TICK_HANDLER));
 
         updateClock();
@@ -97,7 +100,7 @@
         super.onDetachedFromWindow();
 
         mDateFormat = null; // reload the locale next time
-        getContext().unregisterReceiver(mIntentReceiver);
+        mBroadcastDispatcher.unregisterReceiver(mIntentReceiver);
     }
 
     protected void updateClock() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
index 0a40b3c..b6ffd58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
@@ -24,6 +24,7 @@
 import android.provider.Settings.Secure;
 import android.util.Log;
 
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.MainHandler;
 import com.android.systemui.settings.CurrentUserTracker;
 
@@ -49,8 +50,9 @@
     /**
      */
     @Inject
-    public DeviceProvisionedControllerImpl(Context context, @MainHandler Handler mainHandler) {
-        super(context);
+    public DeviceProvisionedControllerImpl(Context context, @MainHandler Handler mainHandler,
+            BroadcastDispatcher broadcastDispatcher) {
+        super(broadcastDispatcher);
         mContext = context;
         mContentResolver = context.getContentResolver();
         mDeviceProvisionedUri = Global.getUriFor(Global.DEVICE_PROVISIONED);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java
index cade5dc..3ce6239 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java
@@ -57,7 +57,7 @@
         ExtensionBuilder<T> withCallback(Consumer<T> callback);
         ExtensionBuilder<T> withUiMode(int mode, Supplier<T> def);
         ExtensionBuilder<T> withFeature(String feature, Supplier<T> def);
-        Extension build();
+        Extension<T> build();
     }
 
     public interface PluginConverter<T, P> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
index fd030d1..eeef726 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
@@ -135,7 +135,7 @@
         }
 
         @Override
-        public ExtensionController.Extension build() {
+        public ExtensionController.Extension<T> build() {
             // Sort items in ascending order
             Collections.sort(mExtension.mProducers, Comparator.comparingInt(Item::sortOrder));
             mExtension.notifyChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 8f201c7..a3a9322 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -19,6 +19,7 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.net.ConnectivityManager;
+import android.net.wifi.WifiClient;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 import android.os.UserManager;
@@ -29,11 +30,13 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.List;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
 /**
+ * Controller used to retrieve information related to a hotspot.
  */
 @Singleton
 public class HotspotControllerImpl implements HotspotController, WifiManager.SoftApCallback {
@@ -48,11 +51,12 @@
     private final Context mContext;
 
     private int mHotspotState;
-    private int mNumConnectedDevices;
+    private volatile int mNumConnectedDevices;
     private boolean mWaitingForTerminalState;
     private boolean mListening;
 
     /**
+     * Controller used to retrieve information related to a hotspot.
      */
     @Inject
     public HotspotControllerImpl(Context context, @MainHandler Handler mainHandler) {
@@ -96,7 +100,6 @@
     /**
      * Adds {@code callback} to the controller. The controller will update the callback on state
      * changes. It will immediately trigger the callback added to notify current state.
-     * @param callback
      */
     @Override
     public void addCallback(Callback callback) {
@@ -110,8 +113,8 @@
                         mWifiManager.registerSoftApCallback(this, mMainHandler);
                     } else {
                         // mWifiManager#registerSoftApCallback triggers a call to
-                        // onNumClientsChanged on the Main Handler. In order to always update the
-                        // callback on added, we make this call when adding callbacks after the
+                        // onConnectedClientsChanged on the Main Handler. In order to always update
+                        // the callback on added, we make this call when adding callbacks after the
                         // first.
                         mMainHandler.post(() ->
                                 callback.onHotspotChanged(isHotspotEnabled(),
@@ -232,8 +235,8 @@
     }
 
     @Override
-    public void onNumClientsChanged(int numConnectedDevices) {
-        mNumConnectedDevices = numConnectedDevices;
+    public void onConnectedClientsChanged(List<WifiClient> clients) {
+        mNumConnectedDevices = clients.size();
         fireHotspotChangedCallback();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 5a97eed..3d51be7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -35,6 +35,7 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.BgLooper;
 import com.android.systemui.util.Utils;
 
@@ -57,6 +58,7 @@
 
     private AppOpsManager mAppOpsManager;
     private StatusBarManager mStatusBarManager;
+    private BroadcastDispatcher mBroadcastDispatcher;
 
     private boolean mAreActiveLocationRequests;
 
@@ -65,14 +67,16 @@
     private final H mHandler = new H();
 
     @Inject
-    public LocationControllerImpl(Context context, @BgLooper Looper bgLooper) {
+    public LocationControllerImpl(Context context, @BgLooper Looper bgLooper,
+            BroadcastDispatcher broadcastDispatcher) {
         mContext = context;
+        mBroadcastDispatcher = broadcastDispatcher;
 
         // Register to listen for changes in location settings.
         IntentFilter filter = new IntentFilter();
         filter.addAction(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
         filter.addAction(LocationManager.MODE_CHANGED_ACTION);
-        context.registerReceiverAsUser(this, UserHandle.ALL, filter, null, new Handler(bgLooper));
+        mBroadcastDispatcher.registerReceiver(this, filter, new Handler(bgLooper), UserHandle.ALL);
 
         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
         mStatusBarManager
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 5da7267..bae51b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -48,6 +48,7 @@
 
 import java.io.PrintWriter;
 import java.util.BitSet;
+import java.util.concurrent.Executor;
 import java.util.Objects;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -103,7 +104,7 @@
         mPhone = phone;
         mDefaults = defaults;
         mSubscriptionInfo = info;
-        mPhoneStateListener = new MobilePhoneStateListener(receiverLooper);
+        mPhoneStateListener = new MobilePhoneStateListener((new Handler(receiverLooper))::post);
         mNetworkNameSeparator = getStringIfExists(R.string.status_bar_network_name_separator);
         mNetworkNameDefault = getStringIfExists(
                 com.android.internal.R.string.lockscreen_carrier_default);
@@ -665,8 +666,8 @@
     }
 
     class MobilePhoneStateListener extends PhoneStateListener {
-        public MobilePhoneStateListener(Looper looper) {
-            super(looper);
+        public MobilePhoneStateListener(Executor executor) {
+            super(executor);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 60784c9..12d3577 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -64,6 +64,7 @@
 import com.android.systemui.DemoMode;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.BgLooper;
 import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
@@ -109,6 +110,7 @@
     private final SubscriptionDefaults mSubDefaults;
     private final DataSaverController mDataSaverController;
     private final CurrentUserTracker mUserTracker;
+    private final BroadcastDispatcher mBroadcastDispatcher;
     private final Object mLock = new Object();
     private Config mConfig;
 
@@ -170,7 +172,8 @@
      */
     @Inject
     public NetworkControllerImpl(Context context, @BgLooper Looper bgLooper,
-            DeviceProvisionedController deviceProvisionedController) {
+            DeviceProvisionedController deviceProvisionedController,
+            BroadcastDispatcher broadcastDispatcher) {
         this(context, (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE),
                 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE),
                 (WifiManager) context.getSystemService(Context.WIFI_SERVICE),
@@ -179,7 +182,8 @@
                 new AccessPointControllerImpl(context),
                 new DataUsageController(context),
                 new SubscriptionDefaults(),
-                deviceProvisionedController);
+                deviceProvisionedController,
+                broadcastDispatcher);
         mReceiverHandler.post(mRegisterListeners);
     }
 
@@ -191,12 +195,14 @@
             AccessPointControllerImpl accessPointController,
             DataUsageController dataUsageController,
             SubscriptionDefaults defaultsHandler,
-            DeviceProvisionedController deviceProvisionedController) {
+            DeviceProvisionedController deviceProvisionedController,
+            BroadcastDispatcher broadcastDispatcher) {
         mContext = context;
         mConfig = config;
         mReceiverHandler = new Handler(bgLooper);
         mCallbackHandler = callbackHandler;
         mDataSaverController = new DataSaverControllerImpl(context);
+        mBroadcastDispatcher = broadcastDispatcher;
 
         mSubscriptionManager = subManager;
         mSubDefaults = defaultsHandler;
@@ -229,7 +235,7 @@
 
         // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
         updateAirplaneMode(true /* force callback */);
-        mUserTracker = new CurrentUserTracker(mContext) {
+        mUserTracker = new CurrentUserTracker(broadcastDispatcher) {
             @Override
             public void onUserSwitched(int newUserId) {
                 NetworkControllerImpl.this.onUserSwitched(newUserId);
@@ -276,7 +282,7 @@
         // exclusively for status bar icons.
         mConnectivityManager.registerDefaultNetworkCallback(callback, mReceiverHandler);
         // Register the listener on our bg looper
-        mPhoneStateListener = new PhoneStateListener(bgLooper) {
+        mPhoneStateListener = new PhoneStateListener(mReceiverHandler::post) {
             @Override
             public void onActiveDataSubscriptionIdChanged(int subId) {
                 mActiveMobileDataSubscription = subId;
@@ -315,7 +321,7 @@
         filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
         filter.addAction(Intent.ACTION_BOOT_COMPLETED);
         filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
-        mContext.registerReceiver(this, filter, null, mReceiverHandler);
+        mBroadcastDispatcher.registerReceiver(this, filter, mReceiverHandler);
         mListening = true;
 
         updateMobileControllers();
@@ -643,7 +649,7 @@
     }
 
     private boolean hasAnySim() {
-        int simCount = mPhone.getSimCount();
+        int simCount = mPhone.getActiveModemCount();
         for (int i = 0; i < simCount; i++) {
             int state = mPhone.getSimState(i);
             if (state != TelephonyManager.SIM_STATE_ABSENT
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java
index 2b60274..7ef9945 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java
@@ -21,7 +21,6 @@
 import android.content.res.Configuration;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.qs.QSFragment;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -40,13 +39,13 @@
     @VisibleForTesting boolean mRemoteInputActive;
     @VisibleForTesting boolean misLandscape;
     private int mLastOrientation;
-    @VisibleForTesting CommandQueue mCommandQueue;
+    private final CommandQueue mCommandQueue;
 
     @Inject
     public RemoteInputQuickSettingsDisabler(Context context,
-            ConfigurationController configController) {
+            ConfigurationController configController, CommandQueue commandQueue) {
         mContext = context;
-        mCommandQueue = SysUiServiceProvider.getComponent(context, CommandQueue.class);
+        mCommandQueue = commandQueue;
         mLastOrientation = mContext.getResources().getConfiguration().orientation;
         configController.addCallback(this);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputUriController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputUriController.java
new file mode 100644
index 0000000..4d912de
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputUriController.java
@@ -0,0 +1,84 @@
+/*
+ * 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.policy;
+
+import android.net.Uri;
+import android.os.RemoteException;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+
+import com.android.internal.statusbar.IStatusBarService;
+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.NotificationEntry;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Handles granting and revoking inline URI grants associated with RemoteInputs.
+ */
+@Singleton
+public class RemoteInputUriController {
+
+    private final IStatusBarService mStatusBarManagerService;
+    private static final String TAG = "RemoteInputUriController";
+
+    @Inject
+    public RemoteInputUriController(IStatusBarService statusBarService) {
+        mStatusBarManagerService = statusBarService;
+    }
+
+    /**
+     * Attach this controller as a listener to the provided NotificationEntryManager to ensure
+     * that RemoteInput URI grants are cleaned up when the notification entry is removed from
+     * the shade.
+     */
+    public void attach(NotificationEntryManager manager) {
+        manager.addNotificationEntryListener(mInlineUriListener);
+    }
+
+    /**
+     * Create a temporary grant which allows the app that submitted the notification access to the
+     * specified URI.
+     */
+    public void grantInlineReplyUriPermission(StatusBarNotification sbn, Uri data) {
+        try {
+            mStatusBarManagerService.grantInlineReplyUriPermission(
+                    sbn.getKey(), data, sbn.getUser(), sbn.getPackageName());
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to grant URI permissions:" + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Ensures that inline URI permissions are cleared when notification entries are removed from
+     * the shade.
+     */
+    private final NotificationEntryListener mInlineUriListener = new NotificationEntryListener() {
+        @Override
+        public void onEntryRemoved(NotificationEntry entry, NotificationVisibility visibility,
+                boolean removedByUser) {
+            try {
+                mStatusBarManagerService.clearInlineReplyUriPermissions(entry.getKey());
+            } catch (RemoteException ex) {
+                ex.rethrowFromSystemServer();
+            }
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 7b4a7d2..307e3bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -173,12 +173,7 @@
     protected Intent prepareRemoteInputFromData(String contentType, Uri data) {
         HashMap<String, Uri> results = new HashMap<>();
         results.put(contentType, data);
-        try {
-            mStatusBarManagerService.grantInlineReplyUriPermission(
-                    mEntry.getSbn().getKey(), data);
-        } catch (Exception e) {
-            Log.e(TAG, "Failed to grant URI permissions:" + e.getMessage(), e);
-        }
+        mController.grantInlineReplyUriPermission(mEntry.getSbn(), data);
         Intent fillInIntent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         RemoteInput.addDataResultToIntent(mRemoteInput, fillInIntent, results);
 
@@ -679,8 +674,8 @@
                         }
                     };
 
-            InputConnection ic = InputConnectionCompat.createWrapper(
-                    inputConnection, outAttrs, callback);
+            InputConnection ic = inputConnection == null ? null :
+                    InputConnectionCompat.createWrapper(inputConnection, outAttrs, callback);
 
             Context userContext = null;
             try {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 6edd75b..c161458 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -48,6 +48,7 @@
 import com.android.internal.net.LegacyVpnInfo;
 import com.android.internal.net.VpnConfig;
 import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.BgHandler;
 import com.android.systemui.settings.CurrentUserTracker;
 
@@ -100,13 +101,14 @@
     /**
      */
     @Inject
-    public SecurityControllerImpl(Context context, @BgHandler Handler bgHandler) {
-        this(context, bgHandler, null);
+    public SecurityControllerImpl(Context context, @BgHandler Handler bgHandler,
+            BroadcastDispatcher broadcastDispatcher) {
+        this(context, bgHandler, broadcastDispatcher, null);
     }
 
     public SecurityControllerImpl(Context context, Handler bgHandler,
-            SecurityControllerCallback callback) {
-        super(context);
+            BroadcastDispatcher broadcastDispatcher, SecurityControllerCallback callback) {
+        super(broadcastDispatcher);
         mContext = context;
         mBgHandler = bgHandler;
         mDevicePolicyManager = (DevicePolicyManager)
@@ -123,8 +125,8 @@
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(KeyChain.ACTION_TRUST_STORE_CHANGED);
-        context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null,
-                bgHandler);
+        filter.addAction(Intent.ACTION_USER_UNLOCKED);
+        broadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, bgHandler, UserHandle.ALL);
 
         // TODO: re-register network callback on user change.
         mConnectivityManager.registerNetworkCallback(REQUEST, mNetworkCallback);
@@ -298,14 +300,11 @@
         } else {
             mVpnUserId = mCurrentUserId;
         }
-        refreshCACerts();
         fireCallbacks();
     }
 
-    private void refreshCACerts() {
-        new CACertLoader().execute(mCurrentUserId);
-        int workProfileId = getWorkProfileUserId(mCurrentUserId);
-        if (workProfileId != UserHandle.USER_NULL) new CACertLoader().execute(workProfileId);
+    private void refreshCACerts(int userId) {
+        new CACertLoader().execute(userId);
     }
 
     private String getNameForVpnConfig(VpnConfig cfg, UserHandle user) {
@@ -401,7 +400,10 @@
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override public void onReceive(Context context, Intent intent) {
             if (KeyChain.ACTION_TRUST_STORE_CHANGED.equals(intent.getAction())) {
-                refreshCACerts();
+                refreshCACerts(getSendingUserId());
+            } else if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
+                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+                if (userId != UserHandle.USER_NULL) refreshCACerts(userId);
             }
         }
     };
@@ -416,9 +418,6 @@
                 return new Pair<Integer, Boolean>(userId[0], hasCACerts);
             } catch (RemoteException | InterruptedException | AssertionError e) {
                 Log.i(TAG, "failed to get CA certs", e);
-                mBgHandler.postDelayed(
-                        () -> new CACertLoader().execute(userId[0]),
-                        CA_CERT_LOADING_RETRY_TIME_IN_MS);
                 return new Pair<Integer, Boolean>(userId[0], null);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 65bb28f..949ac4d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -22,6 +22,7 @@
 import android.text.method.TransformationMethod;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -238,13 +239,15 @@
     public List<Button> inflateSmartActions(Context packageContext,
             @NonNull SmartActions smartActions, SmartReplyController smartReplyController,
             NotificationEntry entry, HeadsUpManager headsUpManager, boolean delayOnClickListener) {
+        Context themedPackageContext = new ContextThemeWrapper(packageContext, mContext.getTheme());
         List<Button> buttons = new ArrayList<>();
         int numSmartActions = smartActions.actions.size();
         for (int n = 0; n < numSmartActions; n++) {
             Notification.Action action = smartActions.actions.get(n);
             if (action.actionIntent != null) {
                 buttons.add(inflateActionButton(
-                        this, getContext(), packageContext, n, smartActions, smartReplyController,
+                        this, getContext(), themedPackageContext, n, smartActions,
+                        smartReplyController,
                         entry, headsUpManager, delayOnClickListener));
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index f2d2fae..13c0db9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.policy;
 
+import static android.os.UserManager.SWITCHABILITY_STATUS_OK;
+
 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 import static com.android.systemui.DejankUtils.whitelistIpcs;
 
@@ -57,6 +59,7 @@
 import com.android.systemui.Prefs.Key;
 import com.android.systemui.R;
 import com.android.systemui.SystemUISecondaryUserService;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.MainHandler;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.DetailAdapter;
@@ -94,6 +97,7 @@
     private final KeyguardStateController mKeyguardStateController;
     protected final Handler mHandler;
     private final ActivityStarter mActivityStarter;
+    private final BroadcastDispatcher mBroadcastDispatcher;
 
     private ArrayList<UserRecord> mUsers = new ArrayList<>();
     private Dialog mExitGuestDialog;
@@ -109,10 +113,12 @@
 
     @Inject
     public UserSwitcherController(Context context, KeyguardStateController keyguardStateController,
-            @MainHandler Handler handler, ActivityStarter activityStarter) {
+            @MainHandler Handler handler, ActivityStarter activityStarter,
+            BroadcastDispatcher broadcastDispatcher) {
         mContext = context;
+        mBroadcastDispatcher = broadcastDispatcher;
         if (!UserManager.isGuestUserEphemeral()) {
-            mGuestResumeSessionReceiver.register(context);
+            mGuestResumeSessionReceiver.register(mBroadcastDispatcher);
         }
         mKeyguardStateController = keyguardStateController;
         mHandler = handler;
@@ -125,8 +131,8 @@
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(Intent.ACTION_USER_STOPPED);
         filter.addAction(Intent.ACTION_USER_UNLOCKED);
-        mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter,
-                null /* permission */, null /* scheduler */);
+        mBroadcastDispatcher.registerReceiver(
+                mReceiver, filter, null /* handler */, UserHandle.SYSTEM);
 
         mSecondaryUserServiceIntent = new Intent(context, SystemUISecondaryUserService.class);
 
@@ -196,7 +202,10 @@
                 }
                 ArrayList<UserRecord> records = new ArrayList<>(infos.size());
                 int currentId = ActivityManager.getCurrentUser();
-                boolean canSwitchUsers = mUserManager.canSwitchUsers();
+                // Check user switchability of the foreground user since SystemUI is running in
+                // User 0
+                boolean canSwitchUsers = mUserManager.getUserSwitchability(
+                        UserHandle.of(ActivityManager.getCurrentUser())) == SWITCHABILITY_STATUS_OK;
                 UserInfo currentUserInfo = null;
                 UserRecord guestRecord = null;
 
@@ -454,8 +463,11 @@
     }
 
     private void listenForCallState() {
-        TelephonyManager.from(mContext).listen(mPhoneStateListener,
-                PhoneStateListener.LISTEN_CALL_STATE);
+        final TelephonyManager tele =
+            (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        if (tele != null) {
+            tele.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+        }
     }
 
     private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index 1c7a195..a2028e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -39,6 +39,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dumpable;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.MainHandler;
 import com.android.systemui.qs.GlobalSetting;
 import com.android.systemui.settings.CurrentUserTracker;
@@ -77,8 +78,9 @@
     private NotificationManager.Policy mConsolidatedNotificationPolicy;
 
     @Inject
-    public ZenModeControllerImpl(Context context, @MainHandler Handler handler) {
-        super(context);
+    public ZenModeControllerImpl(Context context, @MainHandler Handler handler,
+            BroadcastDispatcher broadcastDispatcher) {
+        super(broadcastDispatcher);
         mContext = context;
         mModeSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE) {
             @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java
index d6d0a36..9b685f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java
@@ -30,6 +30,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewPropertyAnimator;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.widget.ImageView;
@@ -45,7 +46,10 @@
     private static final String TAG = "AudioRecordingDisclosureBar";
     private static final boolean DEBUG = false;
 
-    private static final String LAYOUT_PARAMS_TITLE = "AudioRecordingDisclosureBar";
+    // This title is used to test the microphone disclosure indicator in
+    // CtsSystemUiHostTestCases:TvMicrophoneCaptureIndicatorTest
+    private static final String LAYOUT_PARAMS_TITLE = "MicrophoneCaptureIndicator";
+
     private static final int ANIM_DURATION_MS = 150;
 
     private final Context mContext;
@@ -70,6 +74,7 @@
     }
 
     private void createView() {
+        //TODO(b/142228704): this is to be re-implemented once proper design is completed
         mView = View.inflate(mContext,
                 R.layout.tv_status_bar_audio_recording, null);
         mAppsInfoContainer = mView.findViewById(R.id.container);
@@ -88,7 +93,7 @@
                 Context.WINDOW_SERVICE);
         windowManager.addView(mView, layoutParams);
 
-        // Set invisible first util it gains its actual size and we are able to hide it by moving
+        // Set invisible first until it gains its actual size and we are able to hide it by moving
         // off the screen
         mView.setVisibility(View.INVISIBLE);
         mView.getViewTreeObserver().addOnGlobalLayoutListener(
@@ -98,16 +103,18 @@
                         // Now that we get the height, we can move the bar off ("below") the screen
                         final int height = mView.getHeight();
                         mView.setTranslationY(height);
-                        // ... and make it visible
-                        mView.setVisibility(View.VISIBLE);
                         // Remove the observer
                         mView.getViewTreeObserver()
                                 .removeOnGlobalLayoutListener(this);
+                        // Now, that the view has been measured, and the translation was set to
+                        // move it off the screen, we change the visibility to GONE
+                        mView.setVisibility(View.GONE);
                     }
                 });
     }
 
     private void showAudioRecordingDisclosureBar() {
+        mView.setVisibility(View.VISIBLE);
         mView.animate()
                 .translationY(0f)
                 .setDuration(ANIM_DURATION_MS)
@@ -138,9 +145,10 @@
     }
 
     private void hideAudioRecordingDisclosureBar() {
-        mView.animate()
-                .translationY(mView.getHeight())
+        final ViewPropertyAnimator animator = mView.animate();
+        animator.translationY(mView.getHeight())
                 .setDuration(ANIM_DURATION_MS)
+                .withEndAction(() -> mView.setVisibility(View.GONE))
                 .start();
     }
 
@@ -156,7 +164,7 @@
         public void onOpActiveChanged(String op, int uid, String packageName, boolean active) {
             if (DEBUG) {
                 Log.d(TAG,
-                        "OP_RECORD_AUDIO active change, active" + active + ", app=" + packageName);
+                        "OP_RECORD_AUDIO active change, active=" + active + ", app=" + packageName);
             }
 
             if (mExemptApps.contains(packageName)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index c2ed7df..379cf1f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -24,6 +24,9 @@
 import com.android.systemui.SystemUI;
 import com.android.systemui.statusbar.CommandQueue;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
 
 /**
  * Status bar implementation for "large screen" products that mostly present no on-screen nav.
@@ -34,10 +37,15 @@
  * recording, discloses the responsible applications </li>
  * </ul>
  */
+@Singleton
 public class TvStatusBar extends SystemUI implements CommandQueue.Callbacks {
 
-    public TvStatusBar(Context context) {
+    private final CommandQueue mCommandQueue;
+
+    @Inject
+    public TvStatusBar(Context context, CommandQueue commandQueue) {
         super(context);
+        mCommandQueue = commandQueue;
     }
 
     @Override
@@ -46,10 +54,9 @@
 
         final IStatusBarService barService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
-        final CommandQueue commandQueue = getComponent(CommandQueue.class);
-        commandQueue.addCallback(this);
+        mCommandQueue.addCallback(this);
         try {
-            barService.registerStatusBar(commandQueue);
+            barService.registerStatusBar(mCommandQueue);
         } catch (RemoteException ex) {
             // If the system process isn't there we're doomed anyway.
         }
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 9a58a35..128bb21 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -36,6 +36,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 
 import com.google.android.collect.Sets;
 
@@ -45,6 +46,9 @@
 import java.util.Map;
 import java.util.Set;
 
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
 /**
  * Controls the application of theme overlays across the system for all users.
  * This service is responsible for:
@@ -54,15 +58,19 @@
  * - Observing work profile changes and applying overlays from the primary user to their
  * associated work profiles
  */
+@Singleton
 public class ThemeOverlayController extends SystemUI {
     private static final String TAG = "ThemeOverlayController";
     private static final boolean DEBUG = false;
 
     private ThemeOverlayManager mThemeManager;
     private UserManager mUserManager;
+    private BroadcastDispatcher mBroadcastDispatcher;
 
-    public ThemeOverlayController(Context context) {
+    @Inject
+    public ThemeOverlayController(Context context, BroadcastDispatcher broadcastDispatcher) {
         super(context);
+        mBroadcastDispatcher = broadcastDispatcher;
     }
 
     @Override
@@ -78,13 +86,13 @@
         final IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
-        mContext.registerReceiverAsUser(new BroadcastReceiver() {
+        mBroadcastDispatcher.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
                 if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added.");
                 updateThemeOverlays();
             }
-        }, UserHandle.ALL, filter, null, bgHandler);
+        }, filter, bgHandler, UserHandle.ALL);
         mContext.getContentResolver().registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES),
                 false,
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index 2d6027c..ce0032e 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -34,6 +34,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.DemoMode;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.MainHandler;
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.settings.CurrentUserTracker;
@@ -82,7 +83,7 @@
      */
     @Inject
     public TunerServiceImpl(Context context, @MainHandler Handler mainHandler,
-            LeakDetector leakDetector) {
+            LeakDetector leakDetector, BroadcastDispatcher broadcastDispatcher) {
         mContext = context;
         mContentResolver = mContext.getContentResolver();
         mLeakDetector = leakDetector;
@@ -95,7 +96,7 @@
         }
 
         mCurrentUser = ActivityManager.getCurrentUser();
-        mUserTracker = new CurrentUserTracker(mContext) {
+        mUserTracker = new CurrentUserTracker(broadcastDispatcher) {
             @Override
             public void onUserSwitched(int newUserId) {
                 mCurrentUser = newUserId;
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
index 4d12cc9..2f13f39 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
@@ -42,6 +42,9 @@
 import com.android.internal.app.AlertActivity;
 import com.android.internal.app.AlertController;
 import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+
+import javax.inject.Inject;
 
 public class UsbDebuggingActivity extends AlertActivity
                                   implements DialogInterface.OnClickListener {
@@ -49,12 +52,20 @@
 
     private CheckBox mAlwaysAllow;
     private UsbDisconnectedReceiver mDisconnectedReceiver;
+    private final BroadcastDispatcher mBroadcastDispatcher;
     private String mKey;
 
+    @Inject
+    public UsbDebuggingActivity(BroadcastDispatcher broadcastDispatcher) {
+        super();
+        mBroadcastDispatcher = broadcastDispatcher;
+    }
+
     @Override
     public void onCreate(Bundle icicle) {
         Window window = getWindow();
-        window.addSystemFlags(WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+        window.addSystemFlags(
+                WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
         window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
 
         super.onCreate(icicle);
@@ -138,13 +149,13 @@
     public void onStart() {
         super.onStart();
         IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_STATE);
-        registerReceiver(mDisconnectedReceiver, filter);
+        mBroadcastDispatcher.registerReceiver(mDisconnectedReceiver, filter);
     }
 
     @Override
     protected void onStop() {
         if (mDisconnectedReceiver != null) {
-            unregisterReceiver(mDisconnectedReceiver);
+            mBroadcastDispatcher.unregisterReceiver(mDisconnectedReceiver);
         }
         super.onStop();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
index bafd1f1..032b72e 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
@@ -29,10 +29,19 @@
 import com.android.internal.app.AlertActivity;
 import com.android.internal.app.AlertController;
 import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+
+import javax.inject.Inject;
 
 public class UsbDebuggingSecondaryUserActivity extends AlertActivity
         implements DialogInterface.OnClickListener {
     private UsbDisconnectedReceiver mDisconnectedReceiver;
+    private final BroadcastDispatcher mBroadcastDispatcher;
+
+    @Inject
+    public UsbDebuggingSecondaryUserActivity(BroadcastDispatcher broadcastDispatcher) {
+        mBroadcastDispatcher = broadcastDispatcher;
+    }
 
     @Override
     public void onCreate(Bundle icicle) {
@@ -74,13 +83,13 @@
         super.onStart();
 
         IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_STATE);
-        registerReceiver(mDisconnectedReceiver, filter);
+        mBroadcastDispatcher.registerReceiver(mDisconnectedReceiver, filter);
     }
 
     @Override
     protected void onStop() {
         if (mDisconnectedReceiver != null) {
-            unregisterReceiver(mDisconnectedReceiver);
+            mBroadcastDispatcher.unregisterReceiver(mDisconnectedReceiver);
         }
         super.onStop();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
index fa3ff64..2e30d32 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
@@ -35,6 +35,7 @@
 import android.widget.CheckBox;
 
 import com.android.internal.app.ResolverActivity;
+import com.android.internal.app.chooser.TargetInfo;
 import com.android.systemui.R;
 
 import java.util.ArrayList;
@@ -86,8 +87,10 @@
         }
 
         mDevice = (UsbDevice)target.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+        boolean hasAudioCapture = false;
         if (mDevice != null) {
             mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
+            hasAudioCapture = mDevice.getHasAudioCapture();
         } else {
             mAccessory = (UsbAccessory)target.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
             if (mAccessory == null) {
@@ -118,6 +121,8 @@
                 }
             }
         }
+        getIntent().putExtra(
+                ResolverActivity.EXTRA_IS_AUDIO_CAPTURE_DEVICE, hasAudioCapture);
 
         CharSequence title = getResources().getText(com.android.internal.R.string.chooseUsbActivity);
         super.onCreate(savedInstanceState, target, title, null, rList, true);
diff --git a/packages/SystemUI/src/com/android/systemui/util/EmergencyDialerConstants.java b/packages/SystemUI/src/com/android/systemui/util/EmergencyDialerConstants.java
index d101ccb..e93e241 100644
--- a/packages/SystemUI/src/com/android/systemui/util/EmergencyDialerConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/util/EmergencyDialerConstants.java
@@ -21,11 +21,10 @@
  * Please keep these constants being consistent with those in com.android.phone.EmergencyDialer.
  */
 public class EmergencyDialerConstants {
-    // Intent action for emergency dialer activity.
-    public static final String ACTION_DIAL = "com.android.phone.EmergencyDialer.DIAL";
 
     /**
-     * Extra included in {@link #ACTION_DIAL} to indicate the entry type that user starts
+     * Extra included in {@link android.telecom.TelecomManager#createLaunchEmergencyDialerIntent}
+     * to indicate the entry type that user starts
      * the emergency dialer.
      */
     public static final String EXTRA_ENTRY_TYPE =
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index 5ed027d..60d7678 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -37,7 +37,6 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.phone.LockIcon;
 import com.android.systemui.statusbar.phone.NotificationPanelView;
-import com.android.systemui.statusbar.policy.Clock;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -179,11 +178,6 @@
          * Creates the QSCustomizer.
          */
         QSCustomizer createQSCustomizer();
-
-        /**
-         * Creates a Clock.
-         */
-        Clock createClock();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index 92a8d84..47454cb 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -20,9 +20,9 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.provider.Settings;
 import android.view.View;
 
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.CommandQueue;
 
@@ -52,25 +52,25 @@
             View.OnAttachStateChangeListener {
         private final int mMask1;
         private final int mMask2;
+        private final CommandQueue mCommandQueue;
         private View mView;
         private boolean mDisabled;
 
-        public DisableStateTracker(int disableMask, int disable2Mask) {
+        public DisableStateTracker(int disableMask, int disable2Mask, CommandQueue commandQueue) {
             mMask1 = disableMask;
             mMask2 = disable2Mask;
+            mCommandQueue = commandQueue;
         }
 
         @Override
         public void onViewAttachedToWindow(View v) {
             mView = v;
-            SysUiServiceProvider.getComponent(v.getContext(), CommandQueue.class)
-                    .addCallback(this);
+            mCommandQueue.addCallback(this);
         }
 
         @Override
         public void onViewDetachedFromWindow(View v) {
-            SysUiServiceProvider.getComponent(mView.getContext(), CommandQueue.class)
-                    .removeCallback(this);
+            mCommandQueue.removeCallback(this);
             mView = null;
         }
 
@@ -124,4 +124,13 @@
                 && QuickStepContract.isGesturalMode(navMode);
     }
 
+    /**
+     * Allow the media player to be shown in the QS area, controlled by 2 flags.
+     */
+    public static boolean useQsMediaPlayer(Context context) {
+        int flag = Settings.System.getInt(context.getContentResolver(), "qs_media_player", 0);
+        flag |= Settings.System.getInt(context.getContentResolver(), "npv_plugin_flag", 0);
+
+        return flag > 0;
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 57b0987..c1da53b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -26,6 +26,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.never;
@@ -37,6 +38,7 @@
 import android.app.trust.TrustManager;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricSourceType;
@@ -44,6 +46,8 @@
 import android.hardware.face.FaceManager;
 import android.hardware.fingerprint.FingerprintManager;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
@@ -56,7 +60,9 @@
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
+import com.android.systemui.DumpController;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 
 import org.junit.Assert;
@@ -87,6 +93,8 @@
             DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", true, TEST_GROUP_UUID,
             TEST_CARRIER_ID, 0);
     @Mock
+    private DumpController mDumpController;
+    @Mock
     private KeyguardUpdateMonitor.StrongAuthTracker mStrongAuthTracker;
     @Mock
     private TrustManager mTrustManager;
@@ -106,6 +114,8 @@
     private KeyguardBypassController mKeyguardBypassController;
     @Mock
     private SubscriptionManager mSubscriptionManager;
+    @Mock
+    private BroadcastDispatcher mBroadcastDispatcher;
     private TestableLooper mTestableLooper;
     private TestableKeyguardUpdateMonitor mKeyguardUpdateMonitor;
 
@@ -140,6 +150,16 @@
     }
 
     @Test
+    public void testReceiversRegistered() {
+        verify(mBroadcastDispatcher, atLeastOnce()).registerReceiver(
+                eq(mKeyguardUpdateMonitor.mBroadcastReceiver),
+                any(IntentFilter.class), any(Handler.class));
+        verify(mBroadcastDispatcher, atLeastOnce()).registerReceiver(
+                eq(mKeyguardUpdateMonitor.mBroadcastAllReceiver),
+                any(IntentFilter.class), any(Handler.class), eq(UserHandle.ALL));
+    }
+
+    @Test
     public void testIgnoresSimStateCallback_rebroadcast() {
         Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
 
@@ -515,9 +535,9 @@
         AtomicBoolean mSimStateChanged = new AtomicBoolean(false);
 
         protected TestableKeyguardUpdateMonitor(Context context) {
-            super(context, TestableLooper.get(KeyguardUpdateMonitorTest.this).getLooper());
-            context.unregisterReceiver(mBroadcastReceiver);
-            context.unregisterReceiver(mBroadcastAllReceiver);
+            super(context,
+                    TestableLooper.get(KeyguardUpdateMonitorTest.this).getLooper(),
+                    mBroadcastDispatcher, mDumpController);
             mStrongAuthTracker = KeyguardUpdateMonitorTest.this.mStrongAuthTracker;
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
index 939df10..c020514 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
@@ -30,6 +30,7 @@
 import org.junit.Assert;
 import org.junit.Test;
 
+import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
 @SmallTest
@@ -56,10 +57,12 @@
     @Test
     public void testDump() {
         Dumpable d = mock(Dumpable.class);
+        String[] args = new String[0];
+        FileDescriptor fd = mock(FileDescriptor.class);
         mDependency.injectTestDependency(DUMPABLE, d);
         Dependency.get(DUMPABLE);
-        mDependency.dump(null, mock(PrintWriter.class), null);
-        verify(d).dump(eq(null), any(), eq(null));
+        mDependency.dump(fd, mock(PrintWriter.class), args);
+        verify(d).dump(eq(fd), any(), eq(args));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index 5c4ef18..768bd13 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -21,11 +21,15 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.annotation.UserIdInt;
+import android.app.AppOpsManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.os.Bundle;
@@ -42,6 +46,8 @@
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
+import junit.framework.Assert;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -50,27 +56,104 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class ForegroundServiceControllerTest extends SysuiTestCase {
-    @UserIdInt private static final int USERID_ONE = 10; // UserManagerService.MIN_USER_ID;
-    @UserIdInt private static final int USERID_TWO = USERID_ONE + 1;
-
     private ForegroundServiceController mFsc;
     private ForegroundServiceNotificationListener mListener;
     private NotificationEntryListener mEntryListener;
+    private NotificationEntryManager mEntryManager;
 
     @Before
     public void setUp() throws Exception {
-        mFsc = new ForegroundServiceController();
-        NotificationEntryManager notificationEntryManager = mock(NotificationEntryManager.class);
+        mEntryManager = mock(NotificationEntryManager.class);
+        mFsc = new ForegroundServiceController(mEntryManager);
         mListener = new ForegroundServiceNotificationListener(
-                mContext, mFsc, notificationEntryManager);
+                mContext, mFsc, mEntryManager);
         ArgumentCaptor<NotificationEntryListener> entryListenerCaptor =
                 ArgumentCaptor.forClass(NotificationEntryListener.class);
-        verify(notificationEntryManager).addNotificationEntryListener(
+        verify(mEntryManager).addNotificationEntryListener(
                 entryListenerCaptor.capture());
         mEntryListener = entryListenerCaptor.getValue();
     }
 
     @Test
+    public void testAppOps_appOpChangedBeforeNotificationExists() {
+        // GIVEN app op exists, but notification doesn't exist in NEM yet
+        NotificationEntry entry = createFgEntry();
+        mFsc.onAppOpChanged(
+                AppOpsManager.OP_CAMERA,
+                entry.getSbn().getUid(),
+                entry.getSbn().getPackageName(),
+                true);
+        assertFalse(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA));
+
+        // WHEN the notification is added
+        mEntryListener.onPendingEntryAdded(entry);
+
+        // THEN the app op is added to the entry
+        Assert.assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA));
+    }
+
+    @Test
+    public void testAppOps_appOpAddedToForegroundNotif() {
+        // GIVEN a notification associated with a foreground service
+        NotificationEntry entry = addFgEntry();
+        when(mEntryManager.getPendingOrCurrentNotif(entry.getKey())).thenReturn(entry);
+
+        // WHEN we are notified of a new app op for this notification
+        mFsc.onAppOpChanged(
+                AppOpsManager.OP_CAMERA,
+                entry.getSbn().getUid(),
+                entry.getSbn().getPackageName(),
+                true);
+
+        // THEN the app op is added to the entry
+        Assert.assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA));
+
+        // THEN notification views are updated since the notification is visible
+        verify(mEntryManager, times(1)).updateNotifications(anyString());
+    }
+
+    @Test
+    public void testAppOpsAlreadyAdded() {
+        // GIVEN a foreground service associated notification that already has the correct app op
+        NotificationEntry entry = addFgEntry();
+        entry.mActiveAppOps.add(AppOpsManager.OP_CAMERA);
+        when(mEntryManager.getPendingOrCurrentNotif(entry.getKey())).thenReturn(entry);
+
+        // WHEN we are notified of the same app op for this notification
+        mFsc.onAppOpChanged(
+                AppOpsManager.OP_CAMERA,
+                entry.getSbn().getUid(),
+                entry.getSbn().getPackageName(),
+                true);
+
+        // THEN the app op still exists in the notification entry
+        Assert.assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA));
+
+        // THEN notification views aren't updated since nothing changed
+        verify(mEntryManager, never()).updateNotifications(anyString());
+    }
+
+    @Test
+    public void testAppOps_appOpNotAddedToUnrelatedNotif() {
+        // GIVEN no notification entries correspond to the newly updated appOp
+        NotificationEntry entry = addFgEntry();
+        when(mEntryManager.getPendingOrCurrentNotif(entry.getKey())).thenReturn(null);
+
+        // WHEN a new app op is detected
+        mFsc.onAppOpChanged(
+                AppOpsManager.OP_CAMERA,
+                entry.getSbn().getUid(),
+                entry.getSbn().getPackageName(),
+                true);
+
+        // THEN we won't see appOps on the entry
+        Assert.assertFalse(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA));
+
+        // THEN notification views aren't updated since nothing changed
+        verify(mEntryManager, never()).updateNotifications(anyString());
+    }
+
+    @Test
     public void testAppOpsCRUD() {
         // no crash on remove that doesn't exist
         mFsc.onAppOpChanged(9, 1000, "pkg1", false);
@@ -339,12 +422,12 @@
         assertTrue(mFsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1));
     }
 
-    private StatusBarNotification makeMockSBN(int userid, String pkg, int id, String tag,
+    private StatusBarNotification makeMockSBN(int userId, String pkg, int id, String tag,
             int flags) {
         final Notification n = mock(Notification.class);
         n.extras = new Bundle();
         n.flags = flags;
-        return makeMockSBN(userid, pkg, id, tag, n);
+        return makeMockSBN(userId, pkg, id, tag, n);
     }
 
     private StatusBarNotification makeMockSBN(int userid, String pkg, int id, String tag,
@@ -360,10 +443,10 @@
         return sbn;
     }
 
-    private StatusBarNotification makeMockFgSBN(int userid, String pkg, int id,
+    private StatusBarNotification makeMockFgSBN(int uid, String pkg, int id,
             boolean usesStdLayout) {
         StatusBarNotification sbn =
-                makeMockSBN(userid, pkg, id, "foo", Notification.FLAG_FOREGROUND_SERVICE);
+                makeMockSBN(uid, pkg, id, "foo", Notification.FLAG_FOREGROUND_SERVICE);
         if (usesStdLayout) {
             sbn.getNotification().contentView = null;
             sbn.getNotification().headsUpContentView = null;
@@ -374,8 +457,8 @@
         return sbn;
     }
 
-    private StatusBarNotification makeMockFgSBN(int userid, String pkg) {
-        return makeMockSBN(userid, pkg, 1000, "foo", Notification.FLAG_FOREGROUND_SERVICE);
+    private StatusBarNotification makeMockFgSBN(int uid, String pkg) {
+        return makeMockSBN(uid, pkg, 1000, "foo", Notification.FLAG_FOREGROUND_SERVICE);
     }
 
     private StatusBarNotification makeMockDisclosure(int userid, String[] pkgs) {
@@ -392,6 +475,19 @@
         return sbn;
     }
 
+    private NotificationEntry addFgEntry() {
+        NotificationEntry entry = createFgEntry();
+        mEntryListener.onPendingEntryAdded(entry);
+        return entry;
+    }
+
+    private NotificationEntry createFgEntry() {
+        return new NotificationEntryBuilder()
+                .setSbn(makeMockFgSBN(0, TEST_PACKAGE_NAME, 1000, true))
+                .setImportance(NotificationManager.IMPORTANCE_DEFAULT)
+                .build();
+    }
+
     private void entryRemoved(StatusBarNotification notification) {
         mEntryListener.onEntryRemoved(
                 new NotificationEntryBuilder()
@@ -414,6 +510,10 @@
                 .setSbn(notification)
                 .setImportance(importance)
                 .build();
-        mEntryListener.onPostEntryUpdated(entry);
+        mEntryListener.onPreEntryUpdated(entry);
     }
+
+    @UserIdInt private static final int USERID_ONE = 10; // UserManagerService.MIN_USER_ID;
+    @UserIdInt private static final int USERID_TWO = USERID_ONE + 1;
+    private static final String TEST_PACKAGE_NAME = "test";
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index c338d70..1e9000b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -50,6 +50,7 @@
 
 import com.android.systemui.R.dimen;
 import com.android.systemui.ScreenDecorations.TunablePaddingTagListener;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -61,9 +62,13 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import java.util.Collections;
 
+import dagger.Lazy;
+
 @RunWithLooper
 @RunWith(AndroidTestingRunner.class)
 @SmallTest
@@ -71,28 +76,32 @@
 
     private TestableLooper mTestableLooper;
     private ScreenDecorations mScreenDecorations;
-    private StatusBar mStatusBar;
+    @Mock private StatusBar mStatusBar;
     private WindowManager mWindowManager;
     private FragmentService mFragmentService;
     private FragmentHostManager mFragmentHostManager;
-    private TunerService mTunerService;
     private StatusBarWindowView mView;
     private TunablePaddingService mTunablePaddingService;
+    private Handler mMainHandler;
+    @Mock
+    private TunerService mTunerService;
+    @Mock
+    private BroadcastDispatcher mBroadcastDispatcher;
+    @Mock private Lazy<StatusBar> mStatusBarLazy;
 
     @Before
     public void setup() {
+        MockitoAnnotations.initMocks(this);
+
         mTestableLooper = TestableLooper.get(this);
-        mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
-                new Handler(mTestableLooper.getLooper()));
+        mMainHandler = new Handler(mTestableLooper.getLooper());
         mTunablePaddingService = mDependency.injectMockDependency(TunablePaddingService.class);
-        mTunerService = mDependency.injectMockDependency(TunerService.class);
         mFragmentService = mDependency.injectMockDependency(FragmentService.class);
 
-        mStatusBar = mock(StatusBar.class);
         mWindowManager = mock(WindowManager.class);
         mView = spy(new StatusBarWindowView(mContext, null));
+        when(mStatusBarLazy.get()).thenReturn(mStatusBar);
         when(mStatusBar.getStatusBarWindow()).thenReturn(mView);
-        mContext.putComponent(StatusBar.class, mStatusBar);
 
         Display display = mContext.getSystemService(WindowManager.class).getDefaultDisplay();
         when(mWindowManager.getDefaultDisplay()).thenReturn(display);
@@ -102,7 +111,8 @@
         when(mFragmentService.getFragmentHostManager(any())).thenReturn(mFragmentHostManager);
 
 
-        mScreenDecorations = new ScreenDecorations(mContext) {
+        mScreenDecorations = new ScreenDecorations(mContext, mStatusBarLazy, mMainHandler,
+                mBroadcastDispatcher, mTunerService) {
             @Override
             public void start() {
                 super.start();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SizeCompatModeActivityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/SizeCompatModeActivityControllerTest.java
index 06999bc..1638ea1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SizeCompatModeActivityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SizeCompatModeActivityControllerTest.java
@@ -31,6 +31,7 @@
 import com.android.systemui.SizeCompatModeActivityController.RestartActivityButton;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.statusbar.CommandQueue;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -58,7 +59,8 @@
         MockitoAnnotations.initMocks(this);
         doReturn(true).when(mMockButton).show();
 
-        mController = new SizeCompatModeActivityController(mContext, mMockAm) {
+        mController = new SizeCompatModeActivityController(mContext, mMockAm,
+                new CommandQueue(mContext)) {
             @Override
             RestartActivityButton createRestartButton(Context context) {
                 return mMockButton;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SliceBroadcastRelayHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/SliceBroadcastRelayHandlerTest.java
index a766885..7d55623 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SliceBroadcastRelayHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SliceBroadcastRelayHandlerTest.java
@@ -17,6 +17,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
@@ -34,11 +35,14 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.settingslib.SliceBroadcastRelay;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 @RunWith(AndroidTestingRunner.class)
 @SmallTest
@@ -47,11 +51,15 @@
     private static final String TEST_ACTION = "com.android.systemui.action.TEST_ACTION";
     private SliceBroadcastRelayHandler mRelayHandler;
     private Context mSpyContext;
+    @Mock
+    private BroadcastDispatcher mBroadcastDispatcher;
+
     @Before
     public void setup() {
+        MockitoAnnotations.initMocks(this);
         mSpyContext = spy(mContext);
 
-        mRelayHandler = new SliceBroadcastRelayHandler(mSpyContext);
+        mRelayHandler = new SliceBroadcastRelayHandler(mSpyContext, mBroadcastDispatcher);
     }
 
     @Test
@@ -136,6 +144,16 @@
         verify(Receiver.sReceiver, timeout(2000)).onReceive(any(), any());
     }
 
+    @Test
+    public void testRegisteredWithDispatcher() {
+        mRelayHandler.start();
+
+        verify(mBroadcastDispatcher)
+                .registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class));
+        verify(mSpyContext, never())
+                .registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class));
+    }
+
     public static class Receiver extends BroadcastReceiver {
         private static BroadcastReceiver sReceiver;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
index 2c85424..df67637 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
@@ -370,11 +370,6 @@
         public int getMediumToLargeAnimationDurationMs() {
             return 0;
         }
-
-        @Override
-        public int getAnimateCredentialStartDelayMs() {
-            return 0;
-        }
     }
 
     private class TestableBiometricView extends AuthBiometricView {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
index 990f74a..6e438e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.biometrics;
 
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -206,5 +205,10 @@
         public View getPanelView(FrameLayout parent) {
             return mock(View.class);
         }
+
+        @Override
+        public int getAnimateCredentialStartDelayMs() {
+            return 0;
+        }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index b089b74..c215a43 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -88,7 +88,6 @@
         TestableContext context = spy(mContext);
 
         mContext.putComponent(StatusBar.class, mock(StatusBar.class));
-        mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
 
         when(context.getPackageManager()).thenReturn(mPackageManager);
         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE))
@@ -102,7 +101,8 @@
         when(mDialog1.isAllowDeviceCredentials()).thenReturn(false);
         when(mDialog2.isAllowDeviceCredentials()).thenReturn(false);
 
-        mAuthController = new TestableAuthController(context, new MockInjector());
+        mAuthController = new TestableAuthController(
+                context, mock(CommandQueue.class), new MockInjector());
         mAuthController.mComponents = mContext.getComponents();
 
         mAuthController.start();
@@ -389,6 +389,20 @@
         verify(mReceiver).onDialogDismissed(eq(BiometricPrompt.DISMISSED_REASON_USER_CANCEL));
     }
 
+    @Test
+    public void testDoesNotCrash_whenTryAgainPressedAfterDismissal() {
+        showDialog(Authenticator.TYPE_BIOMETRIC, BiometricPrompt.TYPE_FACE);
+        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED);
+        mAuthController.onTryAgainPressed();
+    }
+
+    @Test
+    public void testDoesNotCrash_whenDeviceCredentialPressedAfterDismissal() {
+        showDialog(Authenticator.TYPE_BIOMETRIC, BiometricPrompt.TYPE_FACE);
+        mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED);
+        mAuthController.onDeviceCredentialPressed();
+    }
+
     // Helpers
 
     private void showDialog(int authenticators, int biometricModality) {
@@ -421,8 +435,8 @@
         private int mBuildCount = 0;
         private Bundle mLastBiometricPromptBundle;
 
-        TestableAuthController(Context context, Injector injector) {
-            super(context, injector);
+        TestableAuthController(Context context, CommandQueue commandQueue, Injector injector) {
+            super(context, commandQueue, injector);
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
index 2bff548..ead14e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
@@ -21,6 +21,7 @@
 import android.content.IntentFilter
 import android.os.Handler
 import android.os.Looper
+import android.os.PatternMatcher
 import android.os.UserHandle
 import android.test.suitebuilder.annotation.SmallTest
 import android.testing.AndroidTestingRunner
@@ -33,6 +34,7 @@
 import org.mockito.ArgumentCaptor
 import org.mockito.Captor
 import org.mockito.Mock
+import org.mockito.Mockito.`when`
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
@@ -48,6 +50,10 @@
         val user1 = UserHandle.of(1)
 
         fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
+        const val TEST_ACTION = "TEST_ACTION"
+        const val TEST_SCHEME = "TEST_SCHEME"
+        const val TEST_PATH = "TEST_PATH"
+        const val TEST_TYPE = "test/type"
     }
 
     @Mock
@@ -83,6 +89,11 @@
                 Handler(testableLooper.looper),
                 testableLooper.looper,
                 mapOf(0 to mockUBRUser0, 1 to mockUBRUser1))
+
+        // These should be valid filters
+        `when`(intentFilter.countActions()).thenReturn(1)
+        `when`(intentFilterOther.countActions()).thenReturn(1)
+        `when`(mockContext.user).thenReturn(user0)
     }
 
     @Test
@@ -129,6 +140,44 @@
         verify(mockUBRUser1, never()).unregisterReceiver(broadcastReceiver)
     }
 
+    @Test(expected = IllegalArgumentException::class)
+    fun testFilterMustContainActions() {
+        val testFilter = IntentFilter()
+        broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun testFilterMustNotContainDataScheme() {
+        val testFilter = IntentFilter(TEST_ACTION).apply {
+            addDataScheme(TEST_SCHEME)
+        }
+        broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun testFilterMustNotContainDataAuthority() {
+        val testFilter = IntentFilter(TEST_ACTION).apply {
+            addDataAuthority(mock(IntentFilter.AuthorityEntry::class.java))
+        }
+        broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun testFilterMustNotContainDataPath() {
+        val testFilter = IntentFilter(TEST_ACTION).apply {
+            addDataPath(TEST_PATH, PatternMatcher.PATTERN_LITERAL)
+        }
+        broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun testFilterMustNotContainDataType() {
+        val testFilter = IntentFilter(TEST_ACTION).apply {
+            addDataType(TEST_TYPE)
+        }
+        broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
+    }
+
     private class TestBroadcastDispatcher(
         context: Context,
         mainHandler: Handler,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index 316b891..2ed0b4f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -45,6 +45,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.util.sensors.FakeSensorManager;
 
 import org.junit.Before;
@@ -66,6 +67,8 @@
     FakeSensorManager mSensorManager;
     @Mock
     DozeHost mDozeHost;
+    @Mock
+    BroadcastDispatcher mBroadcastDispatcher;
     DozeScreenBrightness mScreen;
 
     @Before
@@ -82,7 +85,7 @@
         mSensorManager = new FakeSensorManager(mContext);
         mSensor = mSensorManager.getFakeLightSensor();
         mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
-                mSensor.getSensor(), mDozeHost, null /* handler */,
+                mSensor.getSensor(), mBroadcastDispatcher, mDozeHost, null /* handler */,
                 DEFAULT_BRIGHTNESS, SENSOR_TO_BRIGHTNESS, SENSOR_TO_OPACITY,
                 true /* debuggable */);
     }
@@ -185,7 +188,7 @@
     @Test
     public void testNullSensor() throws Exception {
         mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
-                null /* sensor */, mDozeHost, null /* handler */,
+                null /* sensor */, mBroadcastDispatcher, mDozeHost, null /* handler */,
                 DEFAULT_BRIGHTNESS, SENSOR_TO_BRIGHTNESS, SENSOR_TO_OPACITY,
                 true /* debuggable */);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 756227e..226bf6b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -39,6 +39,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.sensors.AsyncSensorManager;
@@ -66,6 +67,8 @@
     private DozeHost mHost;
     @Mock
     private AlarmManager mAlarmManager;
+    @Mock
+    private BroadcastDispatcher mBroadcastDispatcher;
     private DozeTriggers mTriggers;
     private FakeSensorManager mSensors;
     private Sensor mTapSensor;
@@ -87,7 +90,7 @@
 
         mTriggers = new DozeTriggers(mContext, mMachine, mHost, mAlarmManager, config, parameters,
                 asyncSensorManager, Handler.createAsync(Looper.myLooper()), wakeLock, true,
-                mDockManagerFake, mProximitySensor, mock(DozeLog.class));
+                mDockManagerFake, mProximitySensor, mock(DozeLog.class), mBroadcastDispatcher);
         waitForSensorManager();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 9312ed2..c815279 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -37,6 +37,7 @@
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -60,6 +61,7 @@
     private @Mock StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     private @Mock StatusBarWindowController mStatusBarWindowController;
     private @Mock SystemUIFactory mSystemUIFactory;
+    private @Mock BroadcastDispatcher mBroadcastDispatcher;
 
     private FalsingManagerFake mFalsingManager;
 
@@ -81,7 +83,8 @@
 
         TestableLooper.get(this).runWithLooper(() -> {
             mViewMediator = new KeyguardViewMediator(
-                    mContext, mFalsingManager, mLockPatternUtils, mSystemUIFactory);
+                    mContext, mFalsingManager, mLockPatternUtils, mBroadcastDispatcher,
+                    mSystemUIFactory);
         });
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.java
index 6e726cf..e4c387a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityTest.java
@@ -19,7 +19,10 @@
 import static android.app.ActivityManager.TaskDescription;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.annotation.ColorInt;
@@ -35,7 +38,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.keyguard.WorkLockActivity;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -55,12 +58,13 @@
     private @Mock DevicePolicyManager mDevicePolicyManager;
     private @Mock KeyguardManager mKeyguardManager;
     private @Mock Context mContext;
+    private @Mock BroadcastDispatcher mBroadcastDispatcher;
 
     private WorkLockActivity mActivity;
 
     private static class WorkLockActivityTestable extends WorkLockActivity {
-        WorkLockActivityTestable(Context baseContext) {
-            super();
+        WorkLockActivityTestable(Context baseContext, BroadcastDispatcher broadcastDispatcher) {
+            super(broadcastDispatcher);
             attachBaseContext(baseContext);
         }
     }
@@ -77,7 +81,7 @@
         if (Looper.myLooper() == null) {
             Looper.prepare();
         }
-        mActivity = new WorkLockActivityTestable(mContext);
+        mActivity = new WorkLockActivityTestable(mContext, mBroadcastDispatcher);
     }
 
     @Test
@@ -110,4 +114,11 @@
                 .putExtra(Intent.EXTRA_USER_ID, USER_ID));
         assertEquals(orgColor, mActivity.getPrimaryColor());
     }
+
+    @Test
+    public void testUnregisteredFromDispatcher() {
+        mActivity.unregisterBroadcastReceiver();
+        verify(mBroadcastDispatcher).unregisterReceiver(any());
+        verify(mContext, never()).unregisterReceiver(any());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index 8f4de3f..47b35fd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -22,7 +22,6 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.anyObject;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -60,6 +59,8 @@
 import java.time.Duration;
 import java.util.concurrent.TimeUnit;
 
+import dagger.Lazy;
+
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 @SmallTest
@@ -86,6 +87,8 @@
     private IThermalEventListener mUsbThermalEventListener;
     private IThermalEventListener mSkinThermalEventListener;
     @Mock private BroadcastDispatcher mBroadcastDispatcher;
+    @Mock private Lazy<StatusBar> mStatusBarLazy;
+    @Mock private StatusBar mStatusBar;
 
     @Before
     public void setup() {
@@ -93,7 +96,8 @@
         mMockWarnings = mDependency.injectMockDependency(WarningsUI.class);
         mEnhancedEstimates = mDependency.injectMockDependency(EnhancedEstimates.class);
 
-        mContext.putComponent(StatusBar.class, mock(StatusBar.class));
+        when(mStatusBarLazy.get()).thenReturn(mStatusBar);
+
         mContext.addMockSystemService(Context.POWER_SERVICE, mPowerManager);
 
         createPowerUi();
@@ -682,7 +686,7 @@
     }
 
     private void createPowerUi() {
-        mPowerUI = new PowerUI(mContext, mBroadcastDispatcher);
+        mPowerUI = new PowerUI(mContext, mBroadcastDispatcher, mStatusBarLazy);
         mPowerUI.mComponents = mContext.getComponents();
         mPowerUI.mThermalService = mThermalServiceMock;
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
index 462c82e..098521f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.appops.AppOpItem
 import com.android.systemui.appops.AppOpsController
+import com.android.systemui.broadcast.BroadcastDispatcher
 import org.hamcrest.Matchers.hasItem
 import org.hamcrest.Matchers.not
 import org.hamcrest.Matchers.nullValue
@@ -62,7 +63,6 @@
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.reset
-import org.mockito.Mockito.spy
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyNoMoreInteractions
 import org.mockito.MockitoAnnotations
@@ -89,6 +89,8 @@
     private lateinit var callback: PrivacyItemController.Callback
     @Mock
     private lateinit var userManager: UserManager
+    @Mock
+    private lateinit var broadcastDispatcher: BroadcastDispatcher
     @Captor
     private lateinit var argCaptor: ArgumentCaptor<List<PrivacyItem>>
     @Captor
@@ -99,7 +101,7 @@
     private lateinit var handler: Handler
 
     fun PrivacyItemController(context: Context) =
-            PrivacyItemController(context, appOpsController, handler, handler)
+            PrivacyItemController(context, appOpsController, handler, handler, broadcastDispatcher)
 
     @Before
     fun setup() {
@@ -180,14 +182,12 @@
 
     @Test
     fun testRegisterReceiver_allUsers() {
-        val spiedContext = spy(mContext)
-        val itemController = PrivacyItemController(spiedContext)
-        itemController.addCallback(callback)
+        privacyItemController.addCallback(callback)
         testableLooper.processAllMessages()
-        verify(spiedContext, atLeastOnce()).registerReceiverAsUser(
-                eq(itemController.userSwitcherReceiver), eq(UserHandle.ALL), any(), eq(null),
-                eq(null))
-        verify(spiedContext, never()).unregisterReceiver(eq(itemController.userSwitcherReceiver))
+        verify(broadcastDispatcher, atLeastOnce()).registerReceiver(
+                eq(privacyItemController.userSwitcherReceiver), any(), eq(null), eq(UserHandle.ALL))
+        verify(broadcastDispatcher, never())
+                .unregisterReceiver(eq(privacyItemController.userSwitcherReceiver))
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 4eee230..a31fc3a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -39,9 +39,11 @@
 import com.android.systemui.R;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.SysuiBaseFragmentTest;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.tileimpl.QSFactoryImpl;
 import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.AutoTileManager;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.Clock;
@@ -97,7 +99,8 @@
         QSTileHost host = new QSTileHost(mContext, mock(StatusBarIconController.class),
                 mock(QSFactoryImpl.class), new Handler(), Looper.myLooper(),
                 mock(PluginManager.class), mock(TunerService.class),
-                () -> mock(AutoTileManager.class), mock(DumpController.class));
+                () -> mock(AutoTileManager.class), mock(DumpController.class),
+                mock(BroadcastDispatcher.class));
         qs.setHost(host);
 
         qs.setListening(true);
@@ -136,11 +139,14 @@
 
     @Override
     protected Fragment instantiate(Context context, String className, Bundle arguments) {
+        CommandQueue commandQueue = new CommandQueue(context);
         return new QSFragment(
-                new RemoteInputQuickSettingsDisabler(context, mock(ConfigurationController.class)),
+                new RemoteInputQuickSettingsDisabler(context, mock(ConfigurationController.class),
+                        commandQueue),
                 new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()),
                 context,
                 mock(QSTileHost.class),
-                mock(StatusBarStateController.class));
+                mock(StatusBarStateController.class),
+                commandQueue);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index 7752014..0247c2f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -41,6 +41,7 @@
 import com.android.systemui.DumpController;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.qs.QSFactory;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.qs.tileimpl.QSFactoryImpl;
@@ -84,6 +85,8 @@
     @Mock
     private DumpController mDumpController;
     @Mock
+    private BroadcastDispatcher mBroadcastDispatcher;
+    @Mock
     private QSTile.State mMockState;
     private Handler mHandler;
     private TestableLooper mLooper;
@@ -96,7 +99,7 @@
         mHandler = new Handler(mLooper.getLooper());
         mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler,
                 mLooper.getLooper(),
-                mPluginManager, mTunerService, mAutoTiles, mDumpController);
+                mPluginManager, mTunerService, mAutoTiles, mDumpController, mBroadcastDispatcher);
         setUpTileFactory();
         Settings.Secure.putStringForUser(mContext.getContentResolver(), QSTileHost.TILES_SETTING,
                 "", ActivityManager.getCurrentUser());
@@ -168,9 +171,10 @@
         TestQSTileHost(Context context, StatusBarIconController iconController,
                 QSFactoryImpl defaultFactory, Handler mainHandler, Looper bgLooper,
                 PluginManager pluginManager, TunerService tunerService,
-                Provider<AutoTileManager> autoTiles, DumpController dumpController) {
+                Provider<AutoTileManager> autoTiles, DumpController dumpController,
+                BroadcastDispatcher broadcastDispatcher) {
             super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager,
-                    tunerService, autoTiles, dumpController);
+                    tunerService, autoTiles, dumpController, broadcastDispatcher);
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
index 11b0c69..9e5e582 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
@@ -45,6 +45,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 
 import org.junit.After;
 import org.junit.Before;
@@ -59,6 +60,8 @@
 
     private final PackageManagerAdapter mMockPackageManagerAdapter =
             Mockito.mock(PackageManagerAdapter.class);
+    private final BroadcastDispatcher mMockBroadcastDispatcher =
+            Mockito.mock(BroadcastDispatcher.class);
     private final IQSTileService.Stub mMockTileService = Mockito.mock(IQSTileService.Stub.class);
     private ComponentName mTileServiceComponentName;
     private Intent mTileServiceIntent;
@@ -87,7 +90,8 @@
                 Mockito.mock(IQSService.class), new Tile(),
                 mTileServiceIntent,
                 mUser,
-                mMockPackageManagerAdapter);
+                mMockPackageManagerAdapter,
+                mMockBroadcastDispatcher);
     }
 
     @After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index d18cebb..824c50d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -32,6 +32,7 @@
 
 import com.android.systemui.DumpController;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.qs.tileimpl.QSFactoryImpl;
 import com.android.systemui.shared.plugins.PluginManager;
@@ -45,7 +46,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
 import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
 
@@ -57,21 +60,37 @@
 
     private TileServices mTileService;
     private ArrayList<TileServiceManager> mManagers;
+    @Mock
+    private BroadcastDispatcher mBroadcastDispatcher;
+    @Mock
+    private StatusBarIconController mStatusBarIconController;
+    @Mock
+    private QSFactoryImpl mQSFactory;
+    @Mock
+    private PluginManager mPluginManager;
+    @Mock
+    private  TunerService mTunerService;
+    @Mock
+    private AutoTileManager mAutoTileManager;
+    @Mock
+    private DumpController mDumpController;
 
     @Before
     public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
         mDependency.injectMockDependency(BluetoothController.class);
         mManagers = new ArrayList<>();
         QSTileHost host = new QSTileHost(mContext,
-                mock(StatusBarIconController.class),
-                mock(QSFactoryImpl.class),
+                mStatusBarIconController,
+                mQSFactory,
                 new Handler(),
                 Looper.myLooper(),
-                mock(PluginManager.class),
-                mock(TunerService.class),
-                () -> mock(AutoTileManager.class),
-                mock(DumpController.class));
-        mTileService = new TestTileServices(host, Looper.getMainLooper());
+                mPluginManager,
+                mTunerService,
+                () -> mAutoTileManager,
+                mDumpController,
+                mBroadcastDispatcher);
+        mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher);
     }
 
     @After
@@ -138,12 +157,14 @@
     }
 
     private class TestTileServices extends TileServices {
-        public TestTileServices(QSTileHost host, Looper looper) {
-            super(host, looper);
+        TestTileServices(QSTileHost host, Looper looper,
+                BroadcastDispatcher broadcastDispatcher) {
+            super(host, looper, broadcastDispatcher);
         }
 
         @Override
-        protected TileServiceManager onCreateTileService(ComponentName component, Tile qsTile) {
+        protected TileServiceManager onCreateTileService(ComponentName component, Tile qsTile,
+                BroadcastDispatcher broadcastDispatcher) {
             TileServiceManager manager = mock(TileServiceManager.class);
             mManagers.add(manager);
             when(manager.isLifecycleStarted()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/CurrentUserTrackerTest.java b/packages/SystemUI/tests/src/com/android/systemui/settings/CurrentUserTrackerTest.java
index 4162bc1..1b515c6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/CurrentUserTrackerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/CurrentUserTrackerTest.java
@@ -21,9 +21,12 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 /**
  * Testing functionality of the current user tracker
@@ -33,10 +36,13 @@
 
     private CurrentUserTracker mTracker;
     private CurrentUserTracker.UserReceiver mReceiver;
+    @Mock
+    private BroadcastDispatcher mBroadcastDispatcher;
 
     @Before
     public void setUp() {
-        mReceiver = new CurrentUserTracker.UserReceiver(getContext());
+        MockitoAnnotations.initMocks(this);
+        mReceiver = new CurrentUserTracker.UserReceiver(mBroadcastDispatcher);
         mTracker = new CurrentUserTracker(mReceiver) {
             @Override
             public void onUserSwitched(int newUserId) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java
index cfa4065a..3c66ac6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java
@@ -62,9 +62,9 @@
 
     @Before
     public void setUp() {
-        mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
         mNavigationBarController = spy(
-                new NavigationBarController(mContext, Dependency.get(Dependency.MAIN_HANDLER)));
+                new NavigationBarController(mContext, Dependency.get(Dependency.MAIN_HANDLER),
+                        mock(CommandQueue.class)));
         initializeNavigationBars();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index 85a0fbd..548f7a8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -47,6 +47,7 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -74,6 +75,7 @@
     @Mock private NotificationData mNotificationData;
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
     @Mock private StatusBarKeyguardViewManager mKeyguardViewManager;
+    @Mock private BroadcastDispatcher mBroadcastDispatcher;
 
     private int mCurrentUserId;
     private TestNotificationLockscreenUserManager mLockscreenUserManager;
@@ -194,7 +196,7 @@
     private class TestNotificationLockscreenUserManager
             extends NotificationLockscreenUserManagerImpl {
         public TestNotificationLockscreenUserManager(Context context) {
-            super(context);
+            super(context, mBroadcastDispatcher);
         }
 
         public BroadcastReceiver getBaseBroadcastReceiverForTest() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index 2514c93..a754a00d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -31,6 +31,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.policy.RemoteInputUriController;
 
 import com.google.android.collect.Sets;
 
@@ -57,6 +58,7 @@
     @Mock private NotificationListenerService.RankingMap mRanking;
     @Mock private ExpandableNotificationRow mRow;
     @Mock private StatusBarStateController mStateController;
+    @Mock private RemoteInputUriController mRemoteInputUriController;
 
     // Dependency mocks:
     @Mock private NotificationEntryManager mEntryManager;
@@ -76,7 +78,8 @@
                 mLockscreenUserManager, mSmartReplyController, mEntryManager,
                 () -> mock(ShadeController.class),
                 mStateController,
-                Handler.createAsync(Looper.myLooper()));
+                Handler.createAsync(Looper.myLooper()),
+                mRemoteInputUriController);
         mEntry = new NotificationEntryBuilder()
                 .setPkg(TEST_PACKAGE_NAME)
                 .setOpPkg(TEST_PACKAGE_NAME)
@@ -211,9 +214,11 @@
                 NotificationEntryManager notificationEntryManager,
                 Lazy<ShadeController> shadeController,
                 StatusBarStateController statusBarStateController,
-                Handler mainHandler) {
+                Handler mainHandler,
+                RemoteInputUriController remoteInputUriController) {
             super(context, lockscreenUserManager, smartReplyController, notificationEntryManager,
-                    shadeController, statusBarStateController, mainHandler);
+                    shadeController, statusBarStateController, mainHandler,
+                    remoteInputUriController);
         }
 
         public void setUpWithPresenterForTest(Callback callback,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index 88fb3e1..95ce53c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -42,6 +42,7 @@
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.policy.RemoteInputUriController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -72,6 +73,7 @@
     @Mock private NotificationEntryManager mNotificationEntryManager;
     @Mock private IStatusBarService mIStatusBarService;
     @Mock private StatusBarStateController mStatusBarStateController;
+    @Mock private RemoteInputUriController mRemoteInputUriController;
 
     @Before
     public void setUp() {
@@ -88,7 +90,8 @@
                 mock(NotificationLockscreenUserManager.class), mSmartReplyController,
                 mNotificationEntryManager, () -> mock(ShadeController.class),
                 mStatusBarStateController,
-                Handler.createAsync(Looper.myLooper()));
+                Handler.createAsync(Looper.myLooper()),
+                mRemoteInputUriController);
         mRemoteInputManager.setUpWithCallback(mCallback, mDelegate);
         mNotification = new Notification.Builder(mContext, "")
                 .setSmallIcon(R.drawable.ic_person)
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 ebdf851..b2a5109 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
@@ -82,6 +82,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -139,6 +140,7 @@
     @Mock private RowInflaterTask mAsyncInflationTask;
     @Mock private NotificationRowBinder mMockedRowBinder;
 
+    private int mId;
     private NotificationEntry mEntry;
     private StatusBarNotification mSbn;
     private TestableNotificationEntryManager mEntryManager;
@@ -148,8 +150,12 @@
         private final CountDownLatch mCountDownLatch;
 
         TestableNotificationEntryManager() {
-            super(new NotificationData(mock(NotificationSectionsFeatureManager.class),
-                    mock(NotifLog.class)), mock(NotifLog.class));
+            super(
+                    new NotificationData(
+                            mock(NotificationSectionsFeatureManager.class),
+                            mock(NotifLog.class),
+                            mock(PeopleNotificationIdentifier.class)),
+                    mock(NotifLog.class));
             mCountDownLatch = new CountDownLatch(1);
         }
 
@@ -238,18 +244,7 @@
         when(mListContainer.getViewParentForNotification(any())).thenReturn(
                 new FrameLayout(mContext));
 
-        Notification.Builder n = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setContentTitle("Title")
-                .setContentText("Text");
-
-        mEntry = new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setNotification(n.build())
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .build();
+        mEntry = createNotification();
         mSbn = mEntry.getSbn();
 
         mEntry.expandedIcon = mock(StatusBarIconView.class);
@@ -602,6 +597,22 @@
                 any(NotificationVisibility.class), anyBoolean());
     }
 
+    private NotificationEntry createNotification() {
+        Notification.Builder n = new Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setContentTitle("Title")
+                .setContentText("Text");
+
+        return new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_NAME)
+                .setOpPkg(TEST_PACKAGE_NAME)
+                .setUid(TEST_UID)
+                .setId(mId++)
+                .setNotification(n.build())
+                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
+                .build();
+    }
+
     private Notification.Action createAction() {
         return new Notification.Action.Builder(
                 Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
index 9202c51..c2d2e31 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
@@ -16,24 +16,16 @@
 
 package com.android.systemui.statusbar.notification;
 
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertTrue;
-
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
-import android.app.AppOpsManager;
 import android.app.Notification;
 import android.os.UserHandle;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
-import android.util.ArraySet;
 
 import androidx.test.filters.SmallTest;
 
@@ -46,6 +38,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
@@ -78,8 +71,10 @@
 
     // TODO: Remove this once EntryManager no longer needs to be mocked
     private NotificationData mNotificationData =
-            new NotificationData(new NotificationSectionsFeatureManager(
-                    new DeviceConfigProxyFake(), mContext), mock(NotifLog.class));
+            new NotificationData(
+                    new NotificationSectionsFeatureManager(new DeviceConfigProxyFake(), mContext),
+                    mock(NotifLog.class),
+                    mock(PeopleNotificationIdentifier.class));
 
     private int mNextNotifId = 0;
 
@@ -120,107 +115,6 @@
         verify(mEntryManager).updateNotifications(anyString());
     }
 
-    @Test
-    public void testAppOps_appOpAddedToForegroundNotif() {
-        // GIVEN a notification associated with a foreground service
-        final NotificationEntry entry = buildEntry();
-        mNotificationData.add(entry);
-        when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
-                .thenReturn(entry.getKey());
-
-        // WHEN we are notified of a new app op
-        mController.updateNotificationsForAppOp(
-                AppOpsManager.OP_CAMERA,
-                entry.getSbn().getUid(),
-                entry.getSbn().getPackageName(),
-                true);
-
-        // THEN the app op is added to the entry
-        assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA));
-        // THEN updateNotifications(TEST) is called
-        verify(mEntryManager, times(1)).updateNotifications(anyString());
-    }
-
-    @Test
-    public void testAppOps_appOpAddedToUnrelatedNotif() {
-        // GIVEN No current foreground notifs
-        when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString()))
-                .thenReturn(null);
-
-        // WHEN An unrelated notification gets a new app op
-        mController.updateNotificationsForAppOp(AppOpsManager.OP_CAMERA, 1000, "pkg", true);
-
-        // THEN We never call updateNotifications(TEST)
-        verify(mEntryManager, never()).updateNotifications(anyString());
-    }
-
-    @Test
-    public void testAppOps_addNotificationWithExistingAppOps() {
-        // GIVEN a notification with three associated app ops that is associated with a foreground
-        // service
-        final NotificationEntry entry = buildEntry();
-        mNotificationData.add(entry);
-        ArraySet<Integer> expected = new ArraySet<>();
-        expected.add(3);
-        expected.add(235);
-        expected.add(1);
-        when(mForegroundServiceController.getStandardLayoutKey(
-                entry.getSbn().getUserId(),
-                entry.getSbn().getPackageName())).thenReturn(entry.getKey());
-        when(mForegroundServiceController.getAppOps(entry.getSbn().getUserId(),
-                entry.getSbn().getPackageName())).thenReturn(expected);
-
-        // WHEN the notification is added
-        mEntryListener.onBeforeNotificationAdded(entry);
-
-        // THEN the entry is tagged with all three app ops
-        assertEquals(expected.size(), entry.mActiveAppOps.size());
-        for (int op : expected) {
-            assertTrue("Entry missing op " + op, entry.mActiveAppOps.contains(op));
-        }
-    }
-
-    @Test
-    public void testAdd_addNotificationWithNoExistingAppOps() {
-        // GIVEN a notification with NO associated app ops
-        final NotificationEntry entry = buildEntry();
-
-        mNotificationData.add(entry);
-        when(mForegroundServiceController.getStandardLayoutKey(
-                entry.getSbn().getUserId(),
-                entry.getSbn().getPackageName())).thenReturn(entry.getKey());
-        when(mForegroundServiceController.getAppOps(entry.getSbn().getUserId(),
-                entry.getSbn().getPackageName())).thenReturn(null);
-
-        // WHEN the notification is added
-        mEntryListener.onBeforeNotificationAdded(entry);
-
-        // THEN the entry doesn't have any app ops associated with it
-        assertEquals(0, entry.mActiveAppOps.size());
-    }
-
-    @Test
-    public void testAdd_addNonForegroundNotificationWithExistingAppOps() {
-        // GIVEN a notification with app ops that isn't associated with a foreground service
-        final NotificationEntry entry = buildEntry();
-        mNotificationData.add(entry);
-        ArraySet<Integer> ops = new ArraySet<>();
-        ops.add(3);
-        ops.add(235);
-        ops.add(1);
-        when(mForegroundServiceController.getAppOps(entry.getSbn().getUserId(),
-                entry.getSbn().getPackageName())).thenReturn(ops);
-        when(mForegroundServiceController.getStandardLayoutKey(
-                entry.getSbn().getUserId(),
-                entry.getSbn().getPackageName())).thenReturn("something else");
-
-        // WHEN the notification is added
-        mEntryListener.onBeforeNotificationAdded(entry);
-
-        // THEN the entry doesn't have any app ops associated with it
-        assertEquals(0, entry.mActiveAppOps.size());
-    }
-
     private NotificationEntry buildEntry() {
         mNextNotifId++;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
index 640984b..1a469d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar.notification.collection;
 
-import static android.app.AppOpsManager.OP_ACCEPT_HANDOVER;
-import static android.app.AppOpsManager.OP_CAMERA;
 import static android.app.Notification.CATEGORY_ALARM;
 import static android.app.Notification.CATEGORY_CALL;
 import static android.app.Notification.CATEGORY_EVENT;
@@ -56,7 +54,6 @@
 import android.graphics.drawable.Icon;
 import android.media.session.MediaSession;
 import android.os.Bundle;
-import android.os.Process;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.SnoozeCriterion;
@@ -64,7 +61,6 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
-import android.util.ArraySet;
 
 import androidx.test.filters.SmallTest;
 
@@ -81,6 +77,7 @@
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
 import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.ShadeController;
@@ -159,69 +156,6 @@
     }
 
     @Test
-    public void testAllRelevantNotisTaggedWithAppOps() throws Exception {
-        mNotificationData.add(mRow.getEntry());
-        ExpandableNotificationRow row2 = new NotificationTestHelper(getContext(), mDependency)
-                .createRow();
-        mNotificationData.add(row2.getEntry());
-        ExpandableNotificationRow diffPkg =
-                new NotificationTestHelper(getContext(), mDependency).createRow("pkg", 4000,
-                        Process.myUserHandle());
-        mNotificationData.add(diffPkg.getEntry());
-
-        ArraySet<Integer> expectedOps = new ArraySet<>();
-        expectedOps.add(OP_CAMERA);
-        expectedOps.add(OP_ACCEPT_HANDOVER);
-
-        for (int op : expectedOps) {
-            mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
-                    NotificationTestHelper.PKG, mRow.getEntry().getKey(), true);
-            mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
-                    NotificationTestHelper.PKG, row2.getEntry().getKey(), true);
-        }
-        for (int op : expectedOps) {
-            assertTrue(mRow.getEntry().getKey() + " doesn't have op " + op,
-                    mNotificationData.get(mRow.getEntry().getKey()).mActiveAppOps.contains(op));
-            assertTrue(row2.getEntry().getKey() + " doesn't have op " + op,
-                    mNotificationData.get(row2.getEntry().getKey()).mActiveAppOps.contains(op));
-            assertFalse(diffPkg.getEntry().getKey() + " has op " + op,
-                    mNotificationData.get(diffPkg.getEntry().getKey()).mActiveAppOps.contains(op));
-        }
-    }
-
-    @Test
-    public void testAppOpsRemoval() throws Exception {
-        mNotificationData.add(mRow.getEntry());
-        ExpandableNotificationRow row2 = new NotificationTestHelper(getContext(), mDependency)
-                .createRow();
-        mNotificationData.add(row2.getEntry());
-
-        ArraySet<Integer> expectedOps = new ArraySet<>();
-        expectedOps.add(OP_CAMERA);
-        expectedOps.add(OP_ACCEPT_HANDOVER);
-
-        for (int op : expectedOps) {
-            mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
-                    NotificationTestHelper.PKG, row2.getEntry().getKey(), true);
-        }
-
-        expectedOps.remove(OP_ACCEPT_HANDOVER);
-        mNotificationData.updateAppOp(OP_ACCEPT_HANDOVER, NotificationTestHelper.UID,
-                NotificationTestHelper.PKG, row2.getEntry().getKey(), false);
-
-        assertTrue(mRow.getEntry().getKey() + " doesn't have op " + OP_CAMERA,
-                mNotificationData.get(mRow.getEntry().getKey()).mActiveAppOps.contains(OP_CAMERA));
-        assertTrue(row2.getEntry().getKey() + " doesn't have op " + OP_CAMERA,
-                mNotificationData.get(row2.getEntry().getKey()).mActiveAppOps.contains(OP_CAMERA));
-        assertFalse(mRow.getEntry().getKey() + " has op " + OP_ACCEPT_HANDOVER,
-                mNotificationData.get(mRow.getEntry().getKey())
-                        .mActiveAppOps.contains(OP_ACCEPT_HANDOVER));
-        assertFalse(row2.getEntry().getKey() + " has op " + OP_ACCEPT_HANDOVER,
-                mNotificationData.get(row2.getEntry().getKey())
-                        .mActiveAppOps.contains(OP_ACCEPT_HANDOVER));
-    }
-
-    @Test
     public void testGetNotificationsForCurrentUser_shouldFilterNonCurrentUserNotifications()
             throws Exception {
         mNotificationData.add(mRow.getEntry());
@@ -639,7 +573,10 @@
 
     public static class TestableNotificationData extends NotificationData {
         public TestableNotificationData(NotificationSectionsFeatureManager sectionsFeatureManager) {
-            super(sectionsFeatureManager, mock(NotifLog.class));
+            super(
+                    sectionsFeatureManager,
+                    mock(NotifLog.class),
+                    mock(PeopleNotificationIdentifier.class));
         }
 
         public static final String OVERRIDE_RANK = "r";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
new file mode 100644
index 0000000..f5d6f22
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
@@ -0,0 +1,166 @@
+/*
+ * 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.people
+
+import android.app.PendingIntent
+import android.content.Intent
+import android.graphics.drawable.Drawable
+import android.testing.AndroidTestingRunner
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.ActivityStarter
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import kotlin.reflect.KClass
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class PeopleHubViewControllerTest : SysuiTestCase() {
+
+    @JvmField @Rule val mockito: MockitoRule = MockitoJUnit.rule()
+
+    @Mock private lateinit var mockViewBoundary: PeopleHubSectionFooterViewBoundary
+    @Mock private lateinit var mockActivityStarter: ActivityStarter
+
+    @Test
+    fun testBindViewModelToViewBoundary() {
+        val fakePerson1 = fakePersonViewModel("name")
+        val fakeViewModel = PeopleHubViewModel(sequenceOf(fakePerson1), true)
+        val fakePersonViewAdapter1 = FakeDataListener<PersonViewModel?>()
+        val fakePersonViewAdapter2 = FakeDataListener<PersonViewModel?>()
+        val mockClickView = mock(View::class.java)
+        `when`(mockViewBoundary.associatedViewForClickAnimation).thenReturn(mockClickView)
+        `when`(mockViewBoundary.personViewAdapters)
+                .thenReturn(sequenceOf(fakePersonViewAdapter1, fakePersonViewAdapter2))
+        val mockFactory = mock(PeopleHubViewModelFactory::class.java)
+        `when`(mockFactory.createWithAssociatedClickView(any())).thenReturn(fakeViewModel)
+        val mockSubscription = mock(Subscription::class.java)
+        val fakeFactoryDataSource = object : DataSource<PeopleHubViewModelFactory> {
+            override fun registerListener(
+                listener: DataListener<PeopleHubViewModelFactory>
+            ): Subscription {
+                listener.onDataChanged(mockFactory)
+                return mockSubscription
+            }
+        }
+        val adapter = PeopleHubSectionFooterViewAdapterImpl(fakeFactoryDataSource)
+
+        adapter.bindView(mockViewBoundary)
+
+        assertThat(fakePersonViewAdapter1.lastSeen).isEqualTo(Maybe.Just(fakePerson1))
+        assertThat(fakePersonViewAdapter2.lastSeen).isEqualTo(Maybe.Just<PersonViewModel?>(null))
+        verify(mockViewBoundary).setVisible(true)
+        verify(mockFactory).createWithAssociatedClickView(mockClickView)
+    }
+
+    @Test
+    fun testViewModelDataSourceTransformsModel() {
+        val fakeClickIntent = PendingIntent.getActivity(context, 0, Intent("action"), 0)
+        val fakePerson = fakePersonModel("id", "name", fakeClickIntent)
+        val fakeModel = PeopleHubModel(listOf(fakePerson))
+        val mockSubscription = mock(Subscription::class.java)
+        val fakeModelDataSource = object : DataSource<PeopleHubModel> {
+            override fun registerListener(listener: DataListener<PeopleHubModel>): Subscription {
+                listener.onDataChanged(fakeModel)
+                return mockSubscription
+            }
+        }
+        val factoryDataSource = PeopleHubViewModelFactoryDataSourceImpl(
+                mockActivityStarter, fakeModelDataSource)
+        val fakeListener = FakeDataListener<PeopleHubViewModelFactory>()
+        val mockClickView = mock(View::class.java)
+
+        factoryDataSource.registerListener(fakeListener)
+
+        val viewModel = (fakeListener.lastSeen as Maybe.Just).value
+                .createWithAssociatedClickView(mockClickView)
+        assertThat(viewModel.isVisible).isTrue()
+        val people = viewModel.people.toList()
+        assertThat(people.size).isEqualTo(1)
+        assertThat(people[0].name).isEqualTo("name")
+        assertThat(people[0].icon).isSameAs(fakePerson.avatar)
+
+        people[0].onClick()
+
+        verify(mockActivityStarter).startPendingIntentDismissingKeyguard(
+                same(fakeClickIntent),
+                any(),
+                same(mockClickView)
+        )
+    }
+}
+
+/** Works around Mockito matchers returning `null` and breaking non-nullable Kotlin code. */
+private inline fun <reified T : Any> any(): T {
+    return Mockito.any() ?: createInstance(T::class)
+}
+
+/** Works around Mockito matchers returning `null` and breaking non-nullable Kotlin code. */
+private inline fun <reified T : Any> same(value: T): T {
+    return Mockito.same(value) ?: createInstance(T::class)
+}
+
+/** Creates an instance of the given class. */
+private fun <T : Any> createInstance(clazz: KClass<T>): T = castNull()
+
+/** Tricks the Kotlin compiler into assigning `null` to a non-nullable variable. */
+@Suppress("UNCHECKED_CAST")
+private fun <T> castNull(): T = null as T
+
+private fun fakePersonModel(
+    id: String,
+    name: CharSequence,
+    clickIntent: PendingIntent
+): PersonModel =
+        PersonModel(id, name, mock(Drawable::class.java), clickIntent)
+
+private fun fakePersonViewModel(name: CharSequence): PersonViewModel =
+        PersonViewModel(name, mock(Drawable::class.java), mock({}.javaClass))
+
+sealed class Maybe<T> {
+    data class Just<T>(val value: T) : Maybe<T>()
+    class Nothing<T> : Maybe<T>() {
+        override fun equals(other: Any?): Boolean {
+            if (this === other) return true
+            if (javaClass != other?.javaClass) return false
+            return true
+        }
+
+        override fun hashCode(): Int {
+            return javaClass.hashCode()
+        }
+    }
+}
+
+class FakeDataListener<T> : DataListener<T> {
+
+    var lastSeen: Maybe<T> = Maybe.Nothing()
+
+    override fun onDataChanged(data: T) {
+        lastSeen = Maybe.Just(data)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 72bea56..4451fa4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -34,8 +34,11 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
+import android.testing.TestableResources;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.DumpController;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.statusbar.NotificationMediaManager;
@@ -53,6 +56,8 @@
 public class BiometricsUnlockControllerTest extends SysuiTestCase {
 
     @Mock
+    private DumpController mDumpController;
+    @Mock
     private NotificationMediaManager mMediaManager;
     @Mock
     private PowerManager mPowerManager;
@@ -78,11 +83,14 @@
     private KeyguardBypassController mKeyguardBypassController;
     @Mock
     private DozeParameters mDozeParameters;
+    @Mock
+    private MetricsLogger mMetricsLogger;
     private BiometricUnlockController mBiometricUnlockController;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        TestableResources res = getContext().getOrCreateTestableResources();
         when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
         when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true);
         when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
@@ -92,10 +100,11 @@
         mDependency.injectTestDependency(NotificationMediaManager.class, mMediaManager);
         mDependency.injectTestDependency(StatusBarWindowController.class,
                 mStatusBarWindowController);
+        res.addOverride(com.android.internal.R.integer.config_wakeUpDelayDoze, 0);
         mBiometricUnlockController = new BiometricUnlockController(mContext, mDozeScrimController,
                 mKeyguardViewMediator, mScrimController, mStatusBar, mKeyguardStateController,
-                mHandler, mUpdateMonitor, 0 /* wakeUpDelay */, mKeyguardBypassController,
-                mDozeParameters);
+                mHandler, mUpdateMonitor, res.getResources(), mKeyguardBypassController,
+                mDozeParameters, mMetricsLogger, mDumpController);
         mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
new file mode 100644
index 0000000..b05172c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -0,0 +1,224 @@
+/*
+ * 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.phone;
+
+import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.PowerManager;
+import android.testing.AndroidTestingRunner;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.doze.DozeEvent;
+import com.android.systemui.doze.DozeHost;
+import com.android.systemui.doze.DozeLog;
+import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.statusbar.PulseExpansionHandler;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.StatusBarStateControllerImpl;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
+import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+
+import dagger.Lazy;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class DozeServiceHostTest extends SysuiTestCase {
+
+    private DozeServiceHost mDozeServiceHost;
+
+    @Mock private HeadsUpManagerPhone mHeadsUpManager;
+    @Mock private ScrimController mScrimController;
+    @Mock private DozeScrimController mDozeScrimController;
+    @Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
+    @Mock private VisualStabilityManager mVisualStabilityManager;
+    @Mock private KeyguardViewMediator mKeyguardViewMediator;
+    @Mock private StatusBarStateControllerImpl mStatusBarStateController;
+    @Mock private BatteryController mBatteryController;
+    @Mock private DeviceProvisionedController mDeviceProvisionedController;
+    @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    @Mock private AssistManager mAssistManager;
+    @Mock private DozeLog mDozeLog;
+    @Mock private PulseExpansionHandler mPulseExpansionHandler;
+    @Mock private NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
+    @Mock private StatusBarWindowController mStatusBarWindowController;
+    @Mock private PowerManager mPowerManager;
+    @Mock private WakefulnessLifecycle mWakefullnessLifecycle;
+    @Mock private StatusBar mStatusBar;
+    @Mock private NotificationIconAreaController mNotificationIconAreaController;
+    @Mock private StatusBarWindowViewController mStatusBarWindowViewController;
+    @Mock private StatusBarWindowView mStatusBarWindow;
+    @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    @Mock private NotificationPanelView mNotificationPanel;
+    @Mock private View mAmbientIndicationContainer;
+    @Mock private BiometricUnlockController mBiometricUnlockController;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        when(mBiometricUnlockControllerLazy.get()).thenReturn(mBiometricUnlockController);
+        mDozeServiceHost = new DozeServiceHost(mDozeLog, mPowerManager, mWakefullnessLifecycle,
+                mStatusBarStateController, mDeviceProvisionedController, mHeadsUpManager,
+                mBatteryController, mScrimController, mBiometricUnlockControllerLazy,
+                mKeyguardViewMediator, mAssistManager, mDozeScrimController, mKeyguardUpdateMonitor,
+                mVisualStabilityManager, mPulseExpansionHandler, mStatusBarWindowController,
+                mNotificationWakeUpCoordinator);
+
+        mDozeServiceHost.initialize(mStatusBar, mNotificationIconAreaController,
+                mStatusBarWindowViewController, mStatusBarWindow, mStatusBarKeyguardViewManager,
+                mNotificationPanel, mAmbientIndicationContainer);
+    }
+
+    @Test
+    public void testStartStopDozing() {
+        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
+        when(mStatusBarStateController.isKeyguardRequested()).thenReturn(true);
+
+        assertFalse(mDozeServiceHost.getDozingRequested());
+
+        mDozeServiceHost.startDozing();
+        verify(mStatusBarStateController).setIsDozing(eq(true));
+        verify(mStatusBar).updateIsKeyguard();
+
+        mDozeServiceHost.stopDozing();
+        verify(mStatusBarStateController).setIsDozing(eq(false));
+    }
+
+
+    @Test
+    public void testPulseWhileDozing_updatesScrimController() {
+        mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
+        mStatusBar.showKeyguardImpl();
+
+        // Keep track of callback to be able to stop the pulse
+//        DozeHost.PulseCallback[] pulseCallback = new DozeHost.PulseCallback[1];
+//        doAnswer(invocation -> {
+//            pulseCallback[0] = invocation.getArgument(0);
+//            return null;
+//        }).when(mDozeScrimController).pulse(any(), anyInt());
+
+        // Starting a pulse should change the scrim controller to the pulsing state
+        mDozeServiceHost.pulseWhileDozing(new DozeHost.PulseCallback() {
+            @Override
+            public void onPulseStarted() {
+            }
+
+            @Override
+            public void onPulseFinished() {
+            }
+        }, DozeEvent.PULSE_REASON_NOTIFICATION);
+
+        ArgumentCaptor<DozeHost.PulseCallback> pulseCallbackArgumentCaptor =
+                ArgumentCaptor.forClass(DozeHost.PulseCallback.class);
+
+        verify(mDozeScrimController).pulse(
+                pulseCallbackArgumentCaptor.capture(), eq(DozeEvent.PULSE_REASON_NOTIFICATION));
+        verify(mStatusBar).updateScrimController();
+        reset(mStatusBar);
+
+        pulseCallbackArgumentCaptor.getValue().onPulseFinished();
+        assertFalse(mDozeScrimController.isPulsing());
+        verify(mStatusBar).updateScrimController();
+    }
+
+
+    @Test
+    public void testPulseWhileDozingWithDockingReason_suppressWakeUpGesture() {
+        // Keep track of callback to be able to stop the pulse
+        final DozeHost.PulseCallback[] pulseCallback = new DozeHost.PulseCallback[1];
+        doAnswer(invocation -> {
+            pulseCallback[0] = invocation.getArgument(0);
+            return null;
+        }).when(mDozeScrimController).pulse(any(), anyInt());
+
+        // Starting a pulse while docking should suppress wakeup gesture
+        mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class),
+                DozeEvent.PULSE_REASON_DOCKING);
+        verify(mStatusBarWindowViewController).suppressWakeUpGesture(eq(true));
+
+        // Ending a pulse should restore wakeup gesture
+        pulseCallback[0].onPulseFinished();
+        verify(mStatusBarWindowViewController).suppressWakeUpGesture(eq(false));
+    }
+
+    @Test
+    public void testPulseWhileDozing_notifyAuthInterrupt() {
+        HashSet<Integer> reasonsWantingAuth = new HashSet<>(
+                Collections.singletonList(DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN));
+        HashSet<Integer> reasonsSkippingAuth = new HashSet<>(
+                Arrays.asList(DozeEvent.PULSE_REASON_INTENT,
+                        DozeEvent.PULSE_REASON_NOTIFICATION,
+                        DozeEvent.PULSE_REASON_SENSOR_SIGMOTION,
+                        DozeEvent.REASON_SENSOR_PICKUP,
+                        DozeEvent.REASON_SENSOR_DOUBLE_TAP,
+                        DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS,
+                        DozeEvent.PULSE_REASON_DOCKING,
+                        DozeEvent.REASON_SENSOR_WAKE_UP,
+                        DozeEvent.REASON_SENSOR_TAP));
+        HashSet<Integer> reasonsThatDontPulse = new HashSet<>(
+                Arrays.asList(DozeEvent.REASON_SENSOR_PICKUP,
+                        DozeEvent.REASON_SENSOR_DOUBLE_TAP,
+                        DozeEvent.REASON_SENSOR_TAP));
+
+        doAnswer(invocation -> {
+            DozeHost.PulseCallback callback = invocation.getArgument(0);
+            callback.onPulseStarted();
+            return null;
+        }).when(mDozeScrimController).pulse(any(), anyInt());
+
+        mDozeServiceHost.mWakeLockScreenPerformsAuth = true;
+        for (int i = 0; i < DozeEvent.TOTAL_REASONS; i++) {
+            reset(mKeyguardUpdateMonitor);
+            mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class), i);
+            if (reasonsWantingAuth.contains(i)) {
+                verify(mKeyguardUpdateMonitor).onAuthInterruptDetected(eq(true));
+            } else if (reasonsSkippingAuth.contains(i) || reasonsThatDontPulse.contains(i)) {
+                verify(mKeyguardUpdateMonitor, never()).onAuthInterruptDetected(eq(true));
+            } else {
+                throw new AssertionError("Reason " + i + " isn't specified as wanting or skipping"
+                        + " passive auth. Please consider how this pulse reason should behave.");
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index 0216d2e..0260269 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -33,6 +33,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.HeadsUpStatusBarView;
 import com.android.systemui.statusbar.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
@@ -63,6 +64,7 @@
     private KeyguardBypassController mBypassController;
     private NotificationWakeUpCoordinator mWakeUpCoordinator;
     private KeyguardStateController mKeyguardStateController;
+    private CommandQueue mCommandQueue;
 
     @Before
     public void setUp() throws Exception {
@@ -78,6 +80,7 @@
         mBypassController = mock(KeyguardBypassController.class);
         mWakeUpCoordinator = mock(NotificationWakeUpCoordinator.class);
         mKeyguardStateController = mock(KeyguardStateController.class);
+        mCommandQueue = mock(CommandQueue.class);
         mHeadsUpAppearanceController = new HeadsUpAppearanceController(
                 mock(NotificationIconAreaController.class),
                 mHeadsUpManager,
@@ -85,6 +88,7 @@
                 mBypassController,
                 mWakeUpCoordinator,
                 mKeyguardStateController,
+                mCommandQueue,
                 mHeadsUpStatusBarView,
                 mStackScroller,
                 mPanelView,
@@ -163,6 +167,7 @@
                 mBypassController,
                 mWakeUpCoordinator,
                 mKeyguardStateController,
+                mCommandQueue,
                 mHeadsUpStatusBarView,
                 mStackScroller,
                 mPanelView,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java
index b1580ee..0bcc3af 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.phone;
 
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -51,10 +50,10 @@
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
         mDependency.injectMockDependency(KeyguardStateController.class);
         mDependency.injectMockDependency(StatusBarStateController.class);
-        mLightBarTransitionsController = new LightBarTransitionsController(mContext, mApplier);
+        mLightBarTransitionsController = new LightBarTransitionsController(mContext, mApplier,
+                new CommandQueue(mContext));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
index 237f6ac..1255001 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
@@ -124,6 +124,7 @@
     public void setupFragment() throws Exception {
         MockitoAnnotations.initMocks(this);
 
+        mCommandQueue = new CommandQueue(mContext);
         setupSysuiDependency();
         createRootView();
         mOverviewProxyService =
@@ -150,8 +151,6 @@
     }
 
     private void setupSysuiDependency() {
-        mCommandQueue = new CommandQueue(mContext);
-        mSysuiContext.putComponent(CommandQueue.class, mCommandQueue);
         mSysuiContext.putComponent(StatusBar.class, mock(StatusBar.class));
         mSysuiContext.putComponent(Recents.class, mock(Recents.class));
         mSysuiContext.putComponent(Divider.class, mock(Divider.class));
@@ -160,7 +159,6 @@
                 new DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS);
         mSysuiTestableContextExternal = (SysuiTestableContext) mSysuiContext.createDisplayContext(
                 display);
-        mSysuiTestableContextExternal.putComponent(CommandQueue.class, mCommandQueue);
         mSysuiTestableContextExternal.putComponent(StatusBar.class, mock(StatusBar.class));
         mSysuiTestableContextExternal.putComponent(Recents.class, mock(Recents.class));
         mSysuiTestableContextExternal.putComponent(Divider.class, mock(Divider.class));
@@ -252,7 +250,8 @@
                 mock(NavigationModeController.class),
                 mock(StatusBarStateController.class),
                 mMockSysUiState,
-                mBroadcastDispatcher);
+                mBroadcastDispatcher,
+                mCommandQueue);
     }
 
     private class HostCallbacksForExternalDisplay extends
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java
index 1e9378a..27a5002 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java
@@ -54,11 +54,10 @@
         mDependency.injectMockDependency(StatusBarStateController.class);
         mDependency.injectMockDependency(KeyguardStateController.class);
 
-        mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
         NavigationBarView navBar = spy(new NavigationBarView(mContext, null));
         when(navBar.getCurrentView()).thenReturn(navBar);
         when(navBar.findViewById(anyInt())).thenReturn(navBar);
-        mTransitions = new NavigationBarTransitions(navBar);
+        mTransitions = new NavigationBarTransitions(navBar, mock(CommandQueue.class));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index cff6635..280cc90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -45,6 +45,7 @@
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.KeyguardAffordanceView;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationShelf;
@@ -57,6 +58,7 @@
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
 import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -236,13 +238,17 @@
                     mock(PluginManager.class),
                     mock(ShadeController.class),
                     mock(NotificationLockscreenUserManager.class),
-                    new NotificationEntryManager(new NotificationData(mock(
-                            NotificationSectionsFeatureManager.class), mock(NotifLog.class)),
+                    new NotificationEntryManager(
+                            new NotificationData(
+                                    mock(NotificationSectionsFeatureManager.class),
+                                    mock(NotifLog.class),
+                                    mock(PeopleNotificationIdentifier.class)),
                             mock(NotifLog.class)),
                     mock(KeyguardStateController.class),
                     statusBarStateController,
                     mock(DozeLog.class),
-                    mDozeParameters);
+                    mDozeParameters,
+                    new CommandQueue(NotificationPanelViewTest.this.mContext));
             mNotificationStackScroller = mNotificationStackScrollLayout;
             mKeyguardStatusView = NotificationPanelViewTest.this.mKeyguardStatusView;
             mKeyguardStatusBar = NotificationPanelViewTest.this.mKeyguardStatusBar;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 1b132b9..85c247e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -64,6 +64,7 @@
 import org.mockito.MockitoAnnotations;
 import org.mockito.stubbing.Answer;
 
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 
@@ -249,7 +250,7 @@
         finishAnimationsImmediately();
 
         assertScrimAlpha(OPAQUE /* front */,
-                SEMI_TRANSPARENT /* back */,
+                OPAQUE /* back */,
                 TRANSPARENT /* bubble */);
 
         assertScrimTint(true /* front */,
@@ -858,6 +859,22 @@
                 mScrimForBubble.getDefaultFocusHighlightEnabled());
     }
 
+    @Test
+    public void testIsLowPowerMode() {
+        HashSet<ScrimState> lowPowerModeStates = new HashSet<>(Arrays.asList(
+                ScrimState.OFF, ScrimState.AOD, ScrimState.PULSING));
+        HashSet<ScrimState> regularStates = new HashSet<>(Arrays.asList(
+                ScrimState.UNINITIALIZED, ScrimState.KEYGUARD, ScrimState.BOUNCER,
+                ScrimState.BOUNCER_SCRIMMED, ScrimState.BRIGHTNESS_MIRROR, ScrimState.UNLOCKED,
+                ScrimState.BUBBLE_EXPANDED));
+
+        for (ScrimState state : ScrimState.values()) {
+            if (!lowPowerModeStates.contains(state) && !regularStates.contains(state)) {
+                Assert.fail("Scrim state not whitelisted nor blacklisted as low power mode");
+            }
+        }
+    }
+
     private void assertScrimTint(boolean front, boolean behind, boolean bubble) {
         Assert.assertEquals("Tint test failed at state " + mScrimController.getState()
                         + " with scrim: " + getScrimName(mScrimInFront) + " and tint: "
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
index a27ed1e..7b7e2d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
@@ -31,6 +31,7 @@
 
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.StatusBarMobileView;
 import com.android.systemui.statusbar.StatusBarWifiView;
@@ -59,14 +60,14 @@
     @Test
     public void testSetCalledOnAdd_IconManager() {
         LinearLayout layout = new LinearLayout(mContext);
-        TestIconManager manager = new TestIconManager(layout);
+        TestIconManager manager = new TestIconManager(layout, new CommandQueue(mContext));
         testCallOnAdd_forManager(manager);
     }
 
     @Test
     public void testSetCalledOnAdd_DarkIconManager() {
         LinearLayout layout = new LinearLayout(mContext);
-        TestDarkIconManager manager = new TestDarkIconManager(layout);
+        TestDarkIconManager manager = new TestDarkIconManager(layout, new CommandQueue(mContext));
         testCallOnAdd_forManager(manager);
     }
 
@@ -103,8 +104,8 @@
     private static class TestDarkIconManager extends DarkIconManager
             implements TestableIconManager {
 
-        public TestDarkIconManager(LinearLayout group) {
-            super(group);
+        TestDarkIconManager(LinearLayout group, CommandQueue commandQueue) {
+            super(group, commandQueue);
         }
 
         @Override
@@ -138,8 +139,8 @@
     }
 
     private static class TestIconManager extends IconManager implements TestableIconManager {
-        public TestIconManager(ViewGroup group) {
-            super(group);
+        TestIconManager(ViewGroup group, CommandQueue commandQueue) {
+            super(group, commandQueue);
         }
 
         @Override
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 c0c42ef..de87d31 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
@@ -86,7 +86,6 @@
         mMetricsLogger = new FakeMetricsLogger();
         mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
         mCommandQueue = new CommandQueue(mContext);
-        mContext.putComponent(CommandQueue.class, mCommandQueue);
         mDependency.injectTestDependency(StatusBarStateController.class,
                 mock(SysuiStatusBarStateController.class));
         mDependency.injectTestDependency(ShadeController.class, mShadeController);
@@ -115,7 +114,8 @@
                 mock(DozeScrimController.class), mock(ScrimController.class),
                 mock(ActivityLaunchAnimator.class), mock(DynamicPrivacyController.class),
                 mock(NotificationAlertingManager.class),
-                mock(NotificationRowBinderImpl.class), mock(KeyguardStateController.class));
+                mock(NotificationRowBinderImpl.class), mock(KeyguardStateController.class),
+                mCommandQueue);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
index a65f5a5..b1b66b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
@@ -68,12 +68,11 @@
         mDependency.injectTestDependency(ShadeController.class, mShadeController);
         mDependency.injectTestDependency(NotificationLockscreenUserManager.class,
                 mNotificationLockscreenUserManager);
-        mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
 
         mRemoteInputCallback = spy(new StatusBarRemoteInputCallback(mContext,
                 mock(NotificationGroupManager.class), mNotificationLockscreenUserManager,
                 mKeyguardStateController, mStatusBarStateController, mActivityStarter,
-                mShadeController));
+                mShadeController, new CommandQueue(mContext)));
         mRemoteInputCallback.mChallengeReceiver = mRemoteInputCallback.new ChallengeReceiver();
     }
 
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 03d0cea..c21e3ab 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
@@ -61,7 +61,9 @@
 import android.testing.TestableLooper.RunWithLooper;
 import android.util.DisplayMetrics;
 import android.util.SparseArray;
+import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
+import android.widget.LinearLayout;
 
 import androidx.test.filters.SmallTest;
 
@@ -70,6 +72,7 @@
 import com.android.internal.logging.testing.FakeMetricsLogger;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.Dependency;
 import com.android.systemui.ForegroundServiceController;
 import com.android.systemui.InitController;
@@ -82,14 +85,13 @@
 import com.android.systemui.bubbles.BubbleController;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.doze.DozeEvent;
-import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -129,6 +131,7 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
+import com.android.systemui.statusbar.policy.RemoteInputUriController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.util.InjectionInflationController;
@@ -142,9 +145,6 @@
 import java.io.ByteArrayOutputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
 
 import dagger.Lazy;
 
@@ -157,7 +157,6 @@
     private FakeMetricsLogger mMetricsLogger;
     private PowerManager mPowerManager;
     private TestableNotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
-    private CommandQueue mCommandQueue;
 
     @Mock private FeatureFlags mFeatureFlags;
     @Mock private LightBarController mLightBarController;
@@ -173,6 +172,7 @@
     @Mock private ScrimController mScrimController;
     @Mock private DozeScrimController mDozeScrimController;
     @Mock private ArrayList<NotificationEntry> mNotificationList;
+    @Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
     @Mock private BiometricUnlockController mBiometricUnlockController;
     @Mock private NotificationData mNotificationData;
     @Mock private NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor;
@@ -182,6 +182,7 @@
     @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
     @Mock private NotificationRemoteInputManager mRemoteInputManager;
     @Mock private RemoteInputController mRemoteInputController;
+    @Mock private RemoteInputUriController mRemoteInputUriController;
     @Mock private StatusBarStateControllerImpl mStatusBarStateController;
     @Mock private BatteryController mBatteryController;
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
@@ -227,11 +228,18 @@
     @Mock private DozeParameters mDozeParameters;
     @Mock private Lazy<LockscreenWallpaper> mLockscreenWallpaperLazy;
     @Mock private LockscreenWallpaper mLockscreenWallpaper;
+    @Mock private DozeServiceHost mDozeServiceHost;
+    @Mock private LinearLayout mLockIconContainer;
+    @Mock private ViewMediatorCallback mKeyguardVieMediatorCallback;
+    @Mock private KeyguardLiftController mKeyguardLiftController;
+    @Mock private CommandQueue mCommandQueue;
+    @Mock private PluginManager mPluginManager;
 
     @Before
     public void setup() throws Exception {
         MockitoAnnotations.initMocks(this);
         mDependency.injectTestDependency(NotificationFilter.class, mNotificationFilter);
+        mDependency.injectMockDependency(KeyguardDismissUtil.class);
 
         IPowerManager powerManagerService = mock(IPowerManager.class);
         mPowerManager = new PowerManager(mContext, powerManagerService,
@@ -253,9 +261,7 @@
                 mExpansionStateLogger);
         notificationLogger.setVisibilityReporter(mock(Runnable.class));
 
-        mCommandQueue = mock(CommandQueue.class);
         when(mCommandQueue.asBinder()).thenReturn(new Binder());
-        mContext.putComponent(CommandQueue.class, mCommandQueue);
 
         mContext.setTheme(R.style.Theme_SystemUI_Light);
 
@@ -293,6 +299,7 @@
                 .thenReturn(mStatusBarWindowViewController);
 
         when(mLockscreenWallpaperLazy.get()).thenReturn(mLockscreenWallpaper);
+        when(mBiometricUnlockControllerLazy.get()).thenReturn(mBiometricUnlockController);
 
         mStatusBar = new StatusBar(
                 mContext,
@@ -316,7 +323,8 @@
                 mBroadcastDispatcher,
                 new RemoteInputQuickSettingsDisabler(
                         mContext,
-                        configurationController
+                        configurationController,
+                        mCommandQueue
                 ),
                 mNotificationGutsManager,
                 notificationLogger,
@@ -356,24 +364,40 @@
                 mNotifLog,
                 mDozeParameters,
                 mScrimController,
-                mLockscreenWallpaperLazy);
+                mKeyguardLiftController,
+                mLockscreenWallpaperLazy,
+                mBiometricUnlockControllerLazy,
+                mDozeServiceHost,
+                mPowerManager,
+                mDozeScrimController,
+                mCommandQueue,
+                mPluginManager,
+                mRemoteInputUriController);
+
+        when(mStatusBarWindowView.findViewById(R.id.lock_icon_container)).thenReturn(
+                mLockIconContainer);
+
+        when(mKeyguardViewMediator.registerStatusBar(any(StatusBar.class), any(ViewGroup.class),
+                any(NotificationPanelView.class), any(BiometricUnlockController.class),
+                any(ViewGroup.class), any(ViewGroup.class), any(KeyguardBypassController.class)))
+                .thenReturn(mStatusBarKeyguardViewManager);
+
+        when(mKeyguardViewMediator.getViewMediatorCallback()).thenReturn(
+                mKeyguardVieMediatorCallback);
+
         // TODO: we should be able to call mStatusBar.start() and have all the below values
         // initialized automatically.
         mStatusBar.mComponents = mContext.getComponents();
-        mStatusBar.mStatusBarKeyguardViewManager = mStatusBarKeyguardViewManager;
         mStatusBar.mStatusBarWindow = mStatusBarWindowView;
-        mStatusBar.mBiometricUnlockController = mBiometricUnlockController;
         mStatusBar.mNotificationPanel = mNotificationPanelView;
-        mStatusBar.mCommandQueue = mCommandQueue;
         mStatusBar.mDozeScrimController = mDozeScrimController;
         mStatusBar.mNotificationIconAreaController = mNotificationIconAreaController;
         mStatusBar.mPresenter = mNotificationPresenter;
         mStatusBar.mKeyguardIndicationController = mKeyguardIndicationController;
-        mStatusBar.mPowerManager = mPowerManager;
         mStatusBar.mBarService = mBarService;
         mStatusBar.mStackScroller = mStackScroller;
         mStatusBar.mStatusBarWindowViewController = mStatusBarWindowViewController;
-        mStatusBar.putComponent(StatusBar.class, mStatusBar);
+        mStatusBar.startKeyguard();
         Dependency.get(InitController.class).executePostInitTasks();
         entryManager.setUpForTest(mock(NotificationPresenter.class), mStackScroller,
                 mHeadsUpManager);
@@ -383,7 +407,6 @@
 
     @Test
     public void testSetBouncerShowing_noCrash() {
-        mStatusBar.mCommandQueue = mock(CommandQueue.class);
         mStatusBar.setBouncerShowing(true);
     }
 
@@ -737,83 +760,18 @@
         mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
         mStatusBar.showKeyguardImpl();
 
-        // Keep track of callback to be able to stop the pulse
-        DozeHost.PulseCallback[] pulseCallback = new DozeHost.PulseCallback[1];
-        doAnswer(invocation -> {
-            pulseCallback[0] = invocation.getArgument(0);
-            return null;
-        }).when(mDozeScrimController).pulse(any(), anyInt());
-
         // Starting a pulse should change the scrim controller to the pulsing state
-        mStatusBar.mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class),
-                DozeEvent.PULSE_REASON_NOTIFICATION);
+        when(mDozeServiceHost.isPulsing()).thenReturn(true);
+        mStatusBar.updateScrimController();
         verify(mScrimController).transitionTo(eq(ScrimState.PULSING), any());
 
         // Ending a pulse should take it back to keyguard state
-        pulseCallback[0].onPulseFinished();
+        when(mDozeServiceHost.isPulsing()).thenReturn(false);
+        mStatusBar.updateScrimController();
         verify(mScrimController).transitionTo(eq(ScrimState.KEYGUARD));
     }
 
     @Test
-    public void testPulseWhileDozing_notifyAuthInterrupt() {
-        HashSet<Integer> reasonsWantingAuth = new HashSet<>(
-                Collections.singletonList(DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN));
-        HashSet<Integer> reasonsSkippingAuth = new HashSet<>(
-                Arrays.asList(DozeEvent.PULSE_REASON_INTENT,
-                        DozeEvent.PULSE_REASON_NOTIFICATION,
-                        DozeEvent.PULSE_REASON_SENSOR_SIGMOTION,
-                        DozeEvent.REASON_SENSOR_PICKUP,
-                        DozeEvent.REASON_SENSOR_DOUBLE_TAP,
-                        DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS,
-                        DozeEvent.PULSE_REASON_DOCKING,
-                        DozeEvent.REASON_SENSOR_WAKE_UP,
-                        DozeEvent.REASON_SENSOR_TAP));
-        HashSet<Integer> reasonsThatDontPulse = new HashSet<>(
-                Arrays.asList(DozeEvent.REASON_SENSOR_PICKUP,
-                        DozeEvent.REASON_SENSOR_DOUBLE_TAP,
-                        DozeEvent.REASON_SENSOR_TAP));
-
-        doAnswer(invocation -> {
-            DozeHost.PulseCallback callback = invocation.getArgument(0);
-            callback.onPulseStarted();
-            return null;
-        }).when(mDozeScrimController).pulse(any(), anyInt());
-
-        mStatusBar.mDozeServiceHost.mWakeLockScreenPerformsAuth = true;
-        for (int i = 0; i < DozeEvent.TOTAL_REASONS; i++) {
-            reset(mKeyguardUpdateMonitor);
-            mStatusBar.mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class), i);
-            if (reasonsWantingAuth.contains(i)) {
-                verify(mKeyguardUpdateMonitor).onAuthInterruptDetected(eq(true));
-            } else if (reasonsSkippingAuth.contains(i) || reasonsThatDontPulse.contains(i)) {
-                verify(mKeyguardUpdateMonitor, never()).onAuthInterruptDetected(eq(true));
-            } else {
-                throw new AssertionError("Reason " + i + " isn't specified as wanting or skipping"
-                        + " passive auth. Please consider how this pulse reason should behave.");
-            }
-        }
-    }
-
-    @Test
-    public void testPulseWhileDozingWithDockingReason_suppressWakeUpGesture() {
-        // Keep track of callback to be able to stop the pulse
-        final DozeHost.PulseCallback[] pulseCallback = new DozeHost.PulseCallback[1];
-        doAnswer(invocation -> {
-            pulseCallback[0] = invocation.getArgument(0);
-            return null;
-        }).when(mDozeScrimController).pulse(any(), anyInt());
-
-        // Starting a pulse while docking should suppress wakeup gesture
-        mStatusBar.mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class),
-                DozeEvent.PULSE_REASON_DOCKING);
-        verify(mStatusBarWindowViewController).suppressWakeUpGesture(eq(true));
-
-        // Ending a pulse should restore wakeup gesture
-        pulseCallback[0].onPulseFinished();
-        verify(mStatusBarWindowViewController).suppressWakeUpGesture(eq(false));
-    }
-
-    @Test
     public void testSetState_changesIsFullScreenUserSwitcherState() {
         mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
         assertFalse(mStatusBar.isFullScreenUserSwitcherState());
@@ -839,27 +797,17 @@
     }
 
     @Test
-    public void testStartStopDozing() {
-        mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
-        when(mStatusBarStateController.isKeyguardRequested()).thenReturn(true);
-
-        mStatusBar.mDozeServiceHost.startDozing();
-        verify(mStatusBarStateController).setIsDozing(eq(true));
-
-        mStatusBar.mDozeServiceHost.stopDozing();
-        verify(mStatusBarStateController).setIsDozing(eq(false));
-    }
-
-    @Test
     public void testOnStartedWakingUp_isNotDozing() {
         mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
         when(mStatusBarStateController.isKeyguardRequested()).thenReturn(true);
-        mStatusBar.mDozeServiceHost.startDozing();
-        verify(mStatusBarStateController).setIsDozing(eq(true));
+        when(mDozeServiceHost.getDozingRequested()).thenReturn(true);
+        mStatusBar.updateIsKeyguard();
+        // TODO: mNotificationPanelView.expand(false) gets called twice. Should be once.
+        verify(mNotificationPanelView, times(2)).expand(eq(false));
         clearInvocations(mNotificationPanelView);
 
         mStatusBar.mWakefulnessObserver.onStartedWakingUp();
-        verify(mStatusBarStateController).setIsDozing(eq(false));
+        verify(mDozeServiceHost).stopDozing();
         verify(mNotificationPanelView).expand(eq(false));
     }
 
@@ -867,7 +815,8 @@
     public void testOnStartedWakingUp_doesNotDismissBouncer_whenPulsing() {
         mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
         when(mStatusBarStateController.isKeyguardRequested()).thenReturn(true);
-        mStatusBar.mDozeServiceHost.startDozing();
+        when(mDozeServiceHost.getDozingRequested()).thenReturn(true);
+        mStatusBar.updateIsKeyguard();
         clearInvocations(mNotificationPanelView);
 
         mStatusBar.setBouncerShowing(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
index 7c1dfa6..20fb659 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
@@ -31,6 +31,7 @@
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.PulseExpansionHandler;
@@ -96,7 +97,8 @@
                 mKeyguardStateController,
                 mStatusBarStateController,
                 mDozeLog,
-                mDozeParameters)
+                mDozeParameters,
+                new CommandQueue(mContext))
                 .setShadeController(mShadeController)
                 .setStatusBarWindowView(mView)
                 .build();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java
index e626d08..48ed4ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java
@@ -27,6 +27,7 @@
 import android.testing.TestableLooper;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.power.EnhancedEstimates;
 
 import org.junit.Assert;
@@ -44,13 +45,15 @@
 
     @Mock
     private PowerManager mPowerManager;
+    @Mock
+    private BroadcastDispatcher mBroadcastDispatcher;
     private BatteryControllerImpl mBatteryController;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mBatteryController = new BatteryControllerImpl(getContext(), mock(EnhancedEstimates.class),
-                mPowerManager);
+                mPowerManager, mBroadcastDispatcher);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
index 556ed5c..4ccf8a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
@@ -42,6 +42,8 @@
 import org.mockito.MockitoAnnotations;
 import org.mockito.invocation.InvocationOnMock;
 
+import java.util.ArrayList;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
@@ -67,7 +69,8 @@
         mContext.addMockSystemService(WifiManager.class, mWifiManager);
 
         doAnswer((InvocationOnMock invocation) -> {
-            ((WifiManager.SoftApCallback) invocation.getArgument(0)).onNumClientsChanged(1);
+            ((WifiManager.SoftApCallback) invocation.getArgument(0))
+                    .onConnectedClientsChanged(new ArrayList<>());
             return null;
         }).when(mWifiManager).registerSoftApCallback(any(WifiManager.SoftApCallback.class),
                 any(Handler.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
index 3dcb34a..5f772b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
@@ -27,6 +27,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.statusbar.policy.LocationController.LocationChangeCallback;
 
 import org.junit.Before;
@@ -44,7 +45,8 @@
     @Before
     public void setup() {
         mLocationController = spy(new LocationControllerImpl(mContext,
-                TestableLooper.get(this).getLooper()));
+                TestableLooper.get(this).getLooper(),
+                mock(BroadcastDispatcher.class)));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index c03f07e..4d86613 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -56,6 +56,7 @@
 import com.android.settingslib.net.DataUsageController;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
@@ -93,6 +94,7 @@
     protected WifiManager mMockWm;
     protected SubscriptionManager mMockSm;
     protected TelephonyManager mMockTm;
+    protected BroadcastDispatcher mMockBd;
     protected Config mConfig;
     protected CallbackHandler mCallbackHandler;
     protected SubscriptionDefaults mMockSubDefaults;
@@ -130,6 +132,7 @@
         mMockTm = mock(TelephonyManager.class);
         mMockSm = mock(SubscriptionManager.class);
         mMockCm = mock(ConnectivityManager.class);
+        mMockBd = mock(BroadcastDispatcher.class);
         mMockSubDefaults = mock(SubscriptionDefaults.class);
         mNetCapabilities = new NetworkCapabilities();
         when(mMockCm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(true);
@@ -157,7 +160,7 @@
         mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
                 mConfig, TestableLooper.get(this).getLooper(), mCallbackHandler,
                 mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
-                mMockSubDefaults, mMockProvisionController);
+                mMockSubDefaults, mMockProvisionController, mMockBd);
         setupNetworkController();
 
         // Trigger blank callbacks to always get the current state (some tests don't trigger
@@ -208,7 +211,7 @@
                         mConfig, TestableLooper.get(this).getLooper(), mCallbackHandler,
                         mock(AccessPointControllerImpl.class),
                         mock(DataUsageController.class), mMockSubDefaults,
-                        mock(DeviceProvisionedController.class));
+                        mock(DeviceProvisionedController.class), mMockBd);
 
       setupNetworkController();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index aa4723a..ab74caa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -108,7 +108,7 @@
                 mConfig, Looper.getMainLooper(), mCallbackHandler,
                 mock(AccessPointControllerImpl.class),
                 mock(DataUsageController.class), mMockSubDefaults,
-                mock(DeviceProvisionedController.class));
+                mock(DeviceProvisionedController.class), mMockBd);
         setupNetworkController();
 
         setupDefaultSignal();
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 0b53c48..57dcbf2 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
@@ -61,7 +61,7 @@
         mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
                 mConfig, Looper.getMainLooper(), mCallbackHandler,
                 mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
-                mMockSubDefaults, mock(DeviceProvisionedController.class));
+                mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd);
         setupNetworkController();
 
         verifyLastMobileDataIndicators(false, -1, 0);
@@ -123,7 +123,7 @@
         mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
                 mConfig, Looper.getMainLooper(), mCallbackHandler,
                 mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
-                mMockSubDefaults, mock(DeviceProvisionedController.class));
+                mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd);
         setupNetworkController();
 
         // No Subscriptions.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java
index fea3a08..b359b9c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java
@@ -35,12 +35,14 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class RemoteInputQuickSettingsDisablerTest extends SysuiTestCase {
 
+    @Mock
     private CommandQueue mCommandQueue;
     private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
 
@@ -48,11 +50,8 @@
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
-        mCommandQueue = mock(CommandQueue.class);
-        mContext.putComponent(CommandQueue.class, mCommandQueue);
-
         mRemoteInputQuickSettingsDisabler = new RemoteInputQuickSettingsDisabler(mContext,
-                mock(ConfigurationController.class));
+                mock(ConfigurationController.class), mCommandQueue);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
index 854cc2f..0c9130d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
@@ -45,6 +45,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.statusbar.policy.SecurityController.SecurityControllerCallback;
 
 import org.junit.After;
@@ -93,13 +94,13 @@
         when(mKeyChainService.queryLocalInterface("android.security.IKeyChainService"))
                 .thenReturn(mKeyChainService);
 
-        // Wait for callbacks from 1) the CACertLoader and 2) the onUserSwitched() function in the
+        // Wait for callbacks from the onUserSwitched() function in the
         // constructor of mSecurityController
-        mStateChangedLatch = new CountDownLatch(2);
+        mStateChangedLatch = new CountDownLatch(1);
         // TODO: Migrate this test to TestableLooper and use a handler attached
         // to that.
         mSecurityController = new SecurityControllerImpl(mContext,
-                new Handler(Looper.getMainLooper()), this);
+                new Handler(Looper.getMainLooper()), mock(BroadcastDispatcher.class), this);
     }
 
     @After
@@ -169,7 +170,6 @@
         assertTrue(mSecurityController.hasCACertInCurrentUser());
 
         // Exception
-
         mStateChangedLatch = new CountDownLatch(1);
 
         when(mKeyChainService.getUserCaAliases())
@@ -181,9 +181,12 @@
 
         assertFalse(mStateChangedLatch.await(1, TimeUnit.SECONDS));
         assertTrue(mSecurityController.hasCACertInCurrentUser());
-        // The retry takes 30s
-        //assertTrue(mStateChangedLatch.await(31, TimeUnit.SECONDS));
-        //assertFalse(mSecurityController.hasCACertInCurrentUser());
+
+        mSecurityController.new CACertLoader()
+                           .execute(0);
+
+        assertTrue(mStateChangedLatch.await(1, TimeUnit.SECONDS));
+        assertFalse(mSecurityController.hasCACertInCurrentUser());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
index 47e4492..dcf0ef7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
@@ -33,6 +33,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.statusbar.policy.ZenModeController.Callback;
 
 import org.junit.Before;
@@ -51,6 +52,8 @@
     NotificationManager mNm;
     @Mock
     ZenModeConfig mConfig;
+    @Mock
+    BroadcastDispatcher mBroadcastDispatcher;
 
     private ZenModeControllerImpl mController;
 
@@ -60,7 +63,8 @@
         mContext.addMockSystemService(NotificationManager.class, mNm);
         when(mNm.getZenModeConfig()).thenReturn(mConfig);
 
-        mController = new ZenModeControllerImpl(mContext, Handler.createAsync(Looper.myLooper()));
+        mController = new ZenModeControllerImpl(mContext, Handler.createAsync(Looper.myLooper()),
+                mBroadcastDispatcher);
     }
 
     @Test
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
new file mode 100644
index 0000000..61bfb92
--- /dev/null
+++ b/packages/Tethering/Android.bp
@@ -0,0 +1,129 @@
+//
+// 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.
+//
+
+java_defaults {
+    name: "TetheringAndroidLibraryDefaults",
+    platform_apis: true,
+    srcs: [
+        "src/**/*.java",
+        ":framework-tethering-shared-srcs",
+        ":services-tethering-shared-srcs",
+        ":servicescore-tethering-src",
+    ],
+    static_libs: [
+        "androidx.annotation_annotation",
+        "netd_aidl_interface-java",
+        "networkstack-aidl-interfaces-java",
+        "android.hardware.tetheroffload.control-V1.0-java",
+        "tethering-client",
+    ],
+    manifest: "AndroidManifestBase.xml",
+}
+
+// Build tethering static library, used to compile both variants of the tethering.
+android_library {
+    name: "TetheringApiCurrentLib",
+    defaults: ["TetheringAndroidLibraryDefaults"],
+}
+
+cc_library_shared {
+    name: "libtetheroffloadjni",
+    srcs: [
+        "jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp",
+    ],
+    shared_libs: [
+        "libnativehelper",
+        "libcutils",
+        "android.hardware.tetheroffload.config@1.0",
+    ],
+    static_libs: [
+        "liblog",
+        "libbase",
+        "libhidlbase",
+        "libutils",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-Wthread-safety",
+    ],
+}
+
+// Common defaults for compiling the actual APK.
+java_defaults {
+    name: "TetheringAppDefaults",
+    platform_apis: true,
+    privileged: true,
+    jni_libs: [
+        "libtetheroffloadjni",
+    ],
+    resource_dirs: [
+        "res",
+    ],
+    optimize: {
+        proguard_flags_files: ["proguard.flags"],
+    },
+}
+
+// Non-updatable tethering running in the system server process for devices not using the module
+// TODO: build in-process tethering APK here.
+
+// Updatable tethering packaged as an application
+android_app {
+    name: "Tethering",
+    defaults: ["TetheringAppDefaults"],
+    static_libs: ["TetheringApiCurrentLib"],
+    certificate: "networkstack",
+    manifest: "AndroidManifest.xml",
+    use_embedded_native_libs: true,
+    // The permission configuration *must* be included to ensure security of the device
+    required: ["NetworkPermissionConfig"],
+}
+
+// This group will be removed when tethering migration is done.
+filegroup {
+    name: "tethering-servicescore-srcs",
+    srcs: [
+        "src/com/android/server/connectivity/tethering/EntitlementManager.java",
+        "src/com/android/server/connectivity/tethering/OffloadController.java",
+        "src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java",
+        "src/com/android/server/connectivity/tethering/TetheringConfiguration.java",
+        "src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java",
+    ],
+}
+
+// This group will be removed when tethering migration is done.
+filegroup {
+    name: "tethering-servicesnet-srcs",
+    srcs: [
+        "src/android/net/dhcp/DhcpServerCallbacks.java",
+        "src/android/net/dhcp/DhcpServingParamsParcelExt.java",
+        "src/android/net/ip/IpServer.java",
+        "src/android/net/ip/RouterAdvertisementDaemon.java",
+        "src/android/net/util/InterfaceSet.java",
+        "src/android/net/util/PrefixUtils.java",
+    ],
+}
+
+// This group would be removed when tethering migration is done.
+filegroup {
+    name: "tethering-jni-srcs",
+    srcs: [
+        "jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp",
+    ],
+}
diff --git a/packages/Tethering/AndroidManifest.xml b/packages/Tethering/AndroidManifest.xml
new file mode 100644
index 0000000..eb51593
--- /dev/null
+++ b/packages/Tethering/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.tethering"
+          android:sharedUserId="android.uid.networkstack">
+    <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
+
+    <application
+        android:process="com.android.networkstack.process"
+        android:extractNativeLibs="false"
+        android:persistent="true">
+    </application>
+</manifest>
diff --git a/packages/Tethering/AndroidManifestBase.xml b/packages/Tethering/AndroidManifestBase.xml
new file mode 100644
index 0000000..dc013da
--- /dev/null
+++ b/packages/Tethering/AndroidManifestBase.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.tethering"
+          android:versionCode="1"
+          android:versionName="R-initial">
+    <application
+        android:label="Tethering"
+        android:defaultToDeviceProtectedStorage="true"
+        android:directBootAware="true">
+    </application>
+</manifest>
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
new file mode 100644
index 0000000..5b01b1e
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -0,0 +1,40 @@
+//
+// 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.
+//
+
+// AIDL interfaces between the core system and the tethering mainline module.
+aidl_interface {
+    name: "tethering-aidl-interfaces",
+    local_include_dir: "src",
+    srcs: [
+        "src/android/net/ITetheringConnector.aidl",
+    ],
+    backend: {
+        ndk: {
+            enabled: false,
+        },
+        cpp: {
+            enabled: false,
+        },
+    },
+}
+
+java_library {
+    name: "tethering-client",
+    platform_apis: true,
+    static_libs: [
+        "tethering-aidl-interfaces-java",
+    ],
+}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
new file mode 100644
index 0000000..443481e
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
@@ -0,0 +1,20 @@
+/**
+ * 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 perNmissions and
+ * limitations under the License.
+ */
+package android.net;
+
+/** @hide */
+oneway interface ITetheringConnector {
+}
diff --git a/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp b/packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
similarity index 100%
rename from services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
rename to packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
diff --git a/packages/Tethering/proguard.flags b/packages/Tethering/proguard.flags
new file mode 100644
index 0000000..77fc024
--- /dev/null
+++ b/packages/Tethering/proguard.flags
@@ -0,0 +1 @@
+#TBD
diff --git a/packages/Tethering/res/values/config.xml b/packages/Tethering/res/values/config.xml
new file mode 100644
index 0000000..37e679d
--- /dev/null
+++ b/packages/Tethering/res/values/config.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <!--
+    OEMs that wish to change the below settings must do so via a runtime resource overlay package
+    and *NOT* by changing this file. This file is part of the tethering mainline module.
+    -->
+</resources>
diff --git a/services/net/java/android/net/dhcp/DhcpServerCallbacks.java b/packages/Tethering/src/android/net/dhcp/DhcpServerCallbacks.java
similarity index 100%
rename from services/net/java/android/net/dhcp/DhcpServerCallbacks.java
rename to packages/Tethering/src/android/net/dhcp/DhcpServerCallbacks.java
diff --git a/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java b/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java
similarity index 100%
rename from services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java
rename to packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java
diff --git a/services/net/java/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
similarity index 94%
rename from services/net/java/android/net/ip/IpServer.java
rename to packages/Tethering/src/android/net/ip/IpServer.java
index 3d79bba..ff3d7bc 100644
--- a/services/net/java/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -16,7 +16,7 @@
 
 package android.net.ip;
 
-import static android.net.NetworkUtils.numericToInetAddress;
+import static android.net.InetAddresses.parseNumericAddress;
 import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
 import static android.net.util.NetworkConstants.FF;
 import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
@@ -77,6 +77,7 @@
     public static final int STATE_TETHERED    = 2;
     public static final int STATE_LOCAL_ONLY  = 3;
 
+    /** Get string name of |state|.*/
     public static String getStateString(int state) {
         switch (state) {
             case STATE_UNAVAILABLE: return "UNAVAILABLE";
@@ -103,15 +104,16 @@
     // TODO: have this configurable
     private static final int DHCP_LEASE_TIME_SECS = 3600;
 
-    private final static String TAG = "IpServer";
-    private final static boolean DBG = false;
-    private final static boolean VDBG = false;
-    private static final Class[] messageClasses = {
+    private static final String TAG = "IpServer";
+    private static final boolean DBG = false;
+    private static final boolean VDBG = false;
+    private static final Class[] sMessageClasses = {
             IpServer.class
     };
     private static final SparseArray<String> sMagicDecoderRing =
-            MessageUtils.findMessageNames(messageClasses);
+            MessageUtils.findMessageNames(sMessageClasses);
 
+    /** IpServer callback. */
     public static class Callback {
         /**
          * Notify that |who| has changed its tethering state.
@@ -131,11 +133,14 @@
         public void updateLinkProperties(IpServer who, LinkProperties newLp) {}
     }
 
+    /** Capture IpServer dependencies, for injection. */
     public static class Dependencies {
+        /** Create a RouterAdvertisementDaemon instance to be used by IpServer.*/
         public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
             return new RouterAdvertisementDaemon(ifParams);
         }
 
+        /** Get |ifName|'s interface information.*/
         public InterfaceParams getInterfaceParams(String ifName) {
             return InterfaceParams.getByName(ifName);
         }
@@ -244,25 +249,51 @@
         setInitialState(mInitialState);
     }
 
-    public String interfaceName() { return mIfaceName; }
-
-    public int interfaceType() { return mInterfaceType; }
-
-    public int lastError() { return mLastError; }
-
-    public int servingMode() { return mServingMode; }
-
-    public LinkProperties linkProperties() { return new LinkProperties(mLinkProperties); }
-
-    public void stop() { sendMessage(CMD_INTERFACE_DOWN); }
-
-    public void unwanted() { sendMessage(CMD_TETHER_UNREQUESTED); }
+    /** Interface name which IpServer served.*/
+    public String interfaceName() {
+        return mIfaceName;
+    }
 
     /**
-     * Internals.
+     * Tethering downstream type. It would be one of ConnectivityManager#TETHERING_*.
      */
+    public int interfaceType() {
+        return mInterfaceType;
+    }
 
-    private boolean startIPv4() { return configureIPv4(true); }
+    /** Last error from this IpServer. */
+    public int lastError() {
+        return mLastError;
+    }
+
+    /** Serving mode is the current state of IpServer state machine. */
+    public int servingMode() {
+        return mServingMode;
+    }
+
+    /** The properties of the network link which IpServer is serving. */
+    public LinkProperties linkProperties() {
+        return new LinkProperties(mLinkProperties);
+    }
+
+    /** Stop this IpServer. After this is called this IpServer should not be used any more. */
+    public void stop() {
+        sendMessage(CMD_INTERFACE_DOWN);
+    }
+
+    /**
+     * Tethering is canceled. IpServer state machine will be available and wait for
+     * next tethering request.
+     */
+    public void unwanted() {
+        sendMessage(CMD_TETHER_UNREQUESTED);
+    }
+
+    /** Internals. */
+
+    private boolean startIPv4() {
+        return configureIPv4(true);
+    }
 
     /**
      * Convenience wrapper around INetworkStackStatusCallback to run callbacks on the IpServer
@@ -410,7 +441,7 @@
             prefixLen = WIFI_P2P_IFACE_PREFIX_LENGTH;
         } else {
             // BT configures the interface elsewhere: only start DHCP.
-            final Inet4Address srvAddr = (Inet4Address) numericToInetAddress(BLUETOOTH_IFACE_ADDR);
+            final Inet4Address srvAddr = (Inet4Address) parseNumericAddress(BLUETOOTH_IFACE_ADDR);
             return configureDhcp(enabled, srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH);
         }
 
@@ -422,7 +453,7 @@
                 return false;
             }
 
-            InetAddress addr = numericToInetAddress(ipAsString);
+            InetAddress addr = parseNumericAddress(ipAsString);
             linkAddr = new LinkAddress(addr, prefixLen);
             ifcg.setLinkAddress(linkAddr);
             if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
@@ -473,7 +504,7 @@
 
     private String getRandomWifiIPv4Address() {
         try {
-            byte[] bytes = numericToInetAddress(WIFI_HOST_IFACE_ADDR).getAddress();
+            byte[] bytes = parseNumericAddress(WIFI_HOST_IFACE_ADDR).getAddress();
             bytes[3] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1), FF);
             return InetAddress.getByAddress(bytes).getHostAddress();
         } catch (Exception e) {
diff --git a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java b/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
similarity index 88%
rename from services/net/java/android/net/ip/RouterAdvertisementDaemon.java
rename to packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
index 59aea21..4147413 100644
--- a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
+++ b/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
@@ -119,6 +119,7 @@
     private volatile MulticastTransmitter mMulticastTransmitter;
     private volatile UnicastResponder mUnicastResponder;
 
+    /** Encapsulate the RA parameters for RouterAdvertisementDaemon.*/
     public static class RaParams {
         // Tethered traffic will have the hop limit properly decremented.
         // Consequently, set the hoplimit greater by one than the upstream
@@ -150,10 +151,12 @@
             dnses = (HashSet) other.dnses.clone();
         }
 
-        // Returns the subset of RA parameters that become deprecated when
-        // moving from announcing oldRa to announcing newRa.
-        //
-        // Currently only tracks differences in |prefixes| and |dnses|.
+        /**
+         * Returns the subset of RA parameters that become deprecated when
+         * moving from announcing oldRa to announcing newRa.
+         *
+         * Currently only tracks differences in |prefixes| and |dnses|.
+         */
         public static RaParams getDeprecatedRaParams(RaParams oldRa, RaParams newRa) {
             RaParams newlyDeprecated = new RaParams();
 
@@ -179,7 +182,9 @@
         private final HashMap<IpPrefix, Integer> mPrefixes = new HashMap<>();
         private final HashMap<Inet6Address, Integer> mDnses = new HashMap<>();
 
-        Set<IpPrefix> getPrefixes() { return mPrefixes.keySet(); }
+        Set<IpPrefix> getPrefixes() {
+            return mPrefixes.keySet();
+        }
 
         void putPrefixes(Set<IpPrefix> prefixes) {
             for (IpPrefix ipp : prefixes) {
@@ -193,7 +198,9 @@
             }
         }
 
-        Set<Inet6Address> getDnses() { return mDnses.keySet(); }
+        Set<Inet6Address> getDnses() {
+            return mDnses.keySet();
+        }
 
         void putDnses(Set<Inet6Address> dnses) {
             for (Inet6Address dns : dnses) {
@@ -207,7 +214,9 @@
             }
         }
 
-        boolean isEmpty() { return mPrefixes.isEmpty() && mDnses.isEmpty(); }
+        boolean isEmpty() {
+            return mPrefixes.isEmpty() && mDnses.isEmpty();
+        }
 
         private boolean decrementCounters() {
             boolean removed = decrementCounter(mPrefixes);
@@ -219,7 +228,7 @@
             boolean removed = false;
 
             for (Iterator<Map.Entry<T, Integer>> it = map.entrySet().iterator();
-                 it.hasNext();) {
+                    it.hasNext();) {
                 Map.Entry<T, Integer> kv = it.next();
                 if (kv.getValue() == 0) {
                     it.remove();
@@ -240,6 +249,7 @@
         mDeprecatedInfoTracker = new DeprecatedInfoTracker();
     }
 
+    /** Build new RA.*/
     public void buildNewRa(RaParams deprecatedParams, RaParams newParams) {
         synchronized (mLock) {
             if (deprecatedParams != null) {
@@ -260,6 +270,7 @@
         maybeNotifyMulticastTransmitter();
     }
 
+    /** Start router advertisement daemon. */
     public boolean start() {
         if (!createSocket()) {
             return false;
@@ -274,6 +285,7 @@
         return true;
     }
 
+    /** Stop router advertisement daemon. */
     public void stop() {
         closeSocket();
         // Wake up mMulticastTransmitter thread to interrupt a potential 1 day sleep before
@@ -362,8 +374,12 @@
         }
     }
 
-    private static byte asByte(int value) { return (byte) value; }
-    private static short asShort(int value) { return (short) value; }
+    private static byte asByte(int value) {
+        return (byte) value;
+    }
+    private static short asShort(int value) {
+        return (short) value;
+    }
 
     private static void putHeader(ByteBuffer ra, boolean hasDefaultRoute, byte hopLimit) {
         /**
@@ -384,14 +400,14 @@
             +-+-+-+-+-+-+-+-+-+-+-+-
         */
         ra.put(ICMPV6_ND_ROUTER_ADVERT)
-          .put(asByte(0))
-          .putShort(asShort(0))
-          .put(hopLimit)
-          // RFC 4191 "high" preference, iff. advertising a default route.
-          .put(hasDefaultRoute ? asByte(0x08) : asByte(0))
-          .putShort(hasDefaultRoute ? asShort(DEFAULT_LIFETIME) : asShort(0))
-          .putInt(0)
-          .putInt(0);
+                .put(asByte(0))
+                .putShort(asShort(0))
+                .put(hopLimit)
+                // RFC 4191 "high" preference, iff. advertising a default route.
+                .put(hasDefaultRoute ? asByte(0x08) : asByte(0))
+                .putShort(hasDefaultRoute ? asShort(DEFAULT_LIFETIME) : asShort(0))
+                .putInt(0)
+                .putInt(0);
     }
 
     private static void putSlla(ByteBuffer ra, byte[] slla) {
@@ -408,11 +424,12 @@
             // Only IEEE 802.3 6-byte addresses are supported.
             return;
         }
-        final byte ND_OPTION_SLLA = 1;
-        final byte SLLA_NUM_8OCTETS = 1;
-        ra.put(ND_OPTION_SLLA)
-          .put(SLLA_NUM_8OCTETS)
-          .put(slla);
+
+        final byte nd_option_slla = 1;
+        final byte slla_num_8octets = 1;
+        ra.put(nd_option_slla)
+            .put(slla_num_8octets)
+            .put(slla);
     }
 
     private static void putExpandedFlagsOption(ByteBuffer ra) {
@@ -428,13 +445,13 @@
             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
          */
 
-        final byte ND_OPTION_EFO = 26;
-        final byte EFO_NUM_8OCTETS = 1;
+        final byte nd_option__efo = 26;
+        final byte efo_num_8octets = 1;
 
-        ra.put(ND_OPTION_EFO)
-          .put(EFO_NUM_8OCTETS)
-          .putShort(asShort(0))
-          .putInt(0);
+        ra.put(nd_option__efo)
+            .put(efo_num_8octets)
+            .putShort(asShort(0))
+            .putInt(0);
     }
 
     private static void putMtu(ByteBuffer ra, int mtu) {
@@ -449,12 +466,12 @@
             |                              MTU                              |
             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         */
-        final byte ND_OPTION_MTU = 5;
-        final byte MTU_NUM_8OCTETS = 1;
-        ra.put(ND_OPTION_MTU)
-          .put(MTU_NUM_8OCTETS)
-          .putShort(asShort(0))
-          .putInt((mtu < IPV6_MIN_MTU) ? IPV6_MIN_MTU : mtu);
+        final byte nd_option_mtu = 5;
+        final byte mtu_num_8octs = 1;
+        ra.put(nd_option_mtu)
+            .put(mtu_num_8octs)
+            .putShort(asShort(0))
+            .putInt((mtu < IPV6_MIN_MTU) ? IPV6_MIN_MTU : mtu);
     }
 
     private static void putPio(ByteBuffer ra, IpPrefix ipp,
@@ -486,22 +503,22 @@
         if (prefixLength != 64) {
             return;
         }
-        final byte ND_OPTION_PIO = 3;
-        final byte PIO_NUM_8OCTETS = 4;
+        final byte nd_option_pio = 3;
+        final byte pio_num_8octets = 4;
 
         if (validTime < 0) validTime = 0;
         if (preferredTime < 0) preferredTime = 0;
         if (preferredTime > validTime) preferredTime = validTime;
 
         final byte[] addr = ipp.getAddress().getAddress();
-        ra.put(ND_OPTION_PIO)
-          .put(PIO_NUM_8OCTETS)
-          .put(asByte(prefixLength))
-          .put(asByte(0xc0)) /* L & A set */
-          .putInt(validTime)
-          .putInt(preferredTime)
-          .putInt(0)
-          .put(addr);
+        ra.put(nd_option_pio)
+            .put(pio_num_8octets)
+            .put(asByte(prefixLength))
+            .put(asByte(0xc0)) /* L & A set */
+            .putInt(validTime)
+            .putInt(preferredTime)
+            .putInt(0)
+            .put(addr);
     }
 
     private static void putRio(ByteBuffer ra, IpPrefix ipp) {
@@ -524,16 +541,16 @@
         if (prefixLength > 64) {
             return;
         }
-        final byte ND_OPTION_RIO = 24;
-        final byte RIO_NUM_8OCTETS = asByte(
+        final byte nd_option_rio = 24;
+        final byte rio_num_8octets = asByte(
                 (prefixLength == 0) ? 1 : (prefixLength <= 8) ? 2 : 3);
 
         final byte[] addr = ipp.getAddress().getAddress();
-        ra.put(ND_OPTION_RIO)
-          .put(RIO_NUM_8OCTETS)
-          .put(asByte(prefixLength))
-          .put(asByte(0x18))
-          .putInt(DEFAULT_LIFETIME);
+        ra.put(nd_option_rio)
+            .put(rio_num_8octets)
+            .put(asByte(prefixLength))
+            .put(asByte(0x18))
+            .putInt(DEFAULT_LIFETIME);
 
         // Rely upon an IpPrefix's address being properly zeroed.
         if (prefixLength > 0) {
@@ -566,12 +583,12 @@
         }
         if (filteredDnses.isEmpty()) return;
 
-        final byte ND_OPTION_RDNSS = 25;
-        final byte RDNSS_NUM_8OCTETS = asByte(dnses.size() * 2 + 1);
-        ra.put(ND_OPTION_RDNSS)
-          .put(RDNSS_NUM_8OCTETS)
-          .putShort(asShort(0))
-          .putInt(lifetime);
+        final byte nd_option_rdnss = 25;
+        final byte rdnss_num_8octets = asByte(dnses.size() * 2 + 1);
+        ra.put(nd_option_rdnss)
+            .put(rdnss_num_8octets)
+            .putShort(asShort(0))
+            .putInt(lifetime);
 
         for (Inet6Address dns : filteredDnses) {
             // NOTE: If the full of list DNS servers doesn't fit in the packet,
@@ -585,7 +602,7 @@
     }
 
     private boolean createSocket() {
-        final int SEND_TIMEOUT_MS = 300;
+        final int send_timout_ms = 300;
 
         final int oldTag = TrafficStats.getAndSetThreadStatsTag(
                 TrafficStatsConstants.TAG_SYSTEM_NEIGHBOR);
@@ -593,7 +610,7 @@
             mSocket = Os.socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
             // Setting SNDTIMEO is purely for defensive purposes.
             Os.setsockoptTimeval(
-                    mSocket, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(SEND_TIMEOUT_MS));
+                    mSocket, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(send_timout_ms));
             Os.setsockoptIfreq(mSocket, SOL_SOCKET, SO_BINDTODEVICE, mInterface.name);
             NetworkUtils.protectFromVpn(mSocket);
             NetworkUtils.setupRaSocket(mSocket, mInterface.index);
@@ -611,7 +628,7 @@
         if (mSocket != null) {
             try {
                 IoBridge.closeAndSignalBlockedThreads(mSocket);
-            } catch (IOException ignored) {}
+            } catch (IOException ignored) { }
         }
         mSocket = null;
     }
@@ -627,9 +644,9 @@
         }
 
         final InetAddress destip = dest.getAddress();
-        return (destip instanceof Inet6Address) &&
-                destip.isLinkLocalAddress() &&
-               (((Inet6Address) destip).getScopeId() == mInterface.index);
+        return (destip instanceof Inet6Address)
+               && destip.isLinkLocalAddress()
+               && (((Inet6Address) destip).getScopeId() == mInterface.index);
     }
 
     private void maybeSendRA(InetSocketAddress dest) {
@@ -654,11 +671,11 @@
     }
 
     private final class UnicastResponder extends Thread {
-        private final InetSocketAddress solicitor = new InetSocketAddress();
+        private final InetSocketAddress mSolicitor = new InetSocketAddress();
         // The recycled buffer for receiving Router Solicitations from clients.
         // If the RS is larger than IPV6_MIN_MTU the packets are truncated.
         // This is fine since currently only byte 0 is examined anyway.
-        private final byte mSolication[] = new byte[IPV6_MIN_MTU];
+        private final byte[] mSolicitation = new byte[IPV6_MIN_MTU];
 
         @Override
         public void run() {
@@ -666,9 +683,9 @@
                 try {
                     // Blocking receive.
                     final int rval = Os.recvfrom(
-                            mSocket, mSolication, 0, mSolication.length, 0, solicitor);
+                            mSocket, mSolicitation, 0, mSolicitation.length, 0, mSolicitor);
                     // Do the least possible amount of validation.
-                    if (rval < 1 || mSolication[0] != ICMPV6_ND_ROUTER_SOLICIT) {
+                    if (rval < 1 || mSolicitation[0] != ICMPV6_ND_ROUTER_SOLICIT) {
                         continue;
                     }
                 } catch (ErrnoException | SocketException e) {
@@ -678,7 +695,7 @@
                     continue;
                 }
 
-                maybeSendRA(solicitor);
+                maybeSendRA(mSolicitor);
             }
         }
     }
diff --git a/services/net/java/android/net/util/InterfaceSet.java b/packages/Tethering/src/android/net/util/InterfaceSet.java
similarity index 95%
rename from services/net/java/android/net/util/InterfaceSet.java
rename to packages/Tethering/src/android/net/util/InterfaceSet.java
index 9f26fa1..7589787 100644
--- a/services/net/java/android/net/util/InterfaceSet.java
+++ b/packages/Tethering/src/android/net/util/InterfaceSet.java
@@ -47,6 +47,6 @@
     public boolean equals(Object obj) {
         return obj != null
                 && obj instanceof InterfaceSet
-                && ifnames.equals(((InterfaceSet)obj).ifnames);
+                && ifnames.equals(((InterfaceSet) obj).ifnames);
     }
 }
diff --git a/services/net/java/android/net/util/PrefixUtils.java b/packages/Tethering/src/android/net/util/PrefixUtils.java
similarity index 92%
rename from services/net/java/android/net/util/PrefixUtils.java
rename to packages/Tethering/src/android/net/util/PrefixUtils.java
index f60694a..f203e99 100644
--- a/services/net/java/android/net/util/PrefixUtils.java
+++ b/packages/Tethering/src/android/net/util/PrefixUtils.java
@@ -42,16 +42,19 @@
 
     public static final IpPrefix DEFAULT_WIFI_P2P_PREFIX = pfx("192.168.49.0/24");
 
+    /** Get non forwardable prefixes. */
     public static Set<IpPrefix> getNonForwardablePrefixes() {
         final HashSet<IpPrefix> prefixes = new HashSet<>();
         addNonForwardablePrefixes(prefixes);
         return prefixes;
     }
 
+    /** Add non forwardable prefixes. */
     public static void addNonForwardablePrefixes(Set<IpPrefix> prefixes) {
         Collections.addAll(prefixes, MIN_NON_FORWARDABLE_PREFIXES);
     }
 
+    /** Get local prefixes from |lp|. */
     public static Set<IpPrefix> localPrefixesFrom(LinkProperties lp) {
         final HashSet<IpPrefix> localPrefixes = new HashSet<>();
         if (lp == null) return localPrefixes;
@@ -66,10 +69,12 @@
         return localPrefixes;
     }
 
+    /** Convert LinkAddress |addr| to IpPrefix. */
     public static IpPrefix asIpPrefix(LinkAddress addr) {
         return new IpPrefix(addr.getAddress(), addr.getPrefixLength());
     }
 
+    /** Convert InetAddress |ip| to IpPrefix. */
     public static IpPrefix ipAddressAsPrefix(InetAddress ip) {
         final int bitLength = (ip instanceof Inet4Address)
                 ? NetworkConstants.IPV4_ADDR_BITS
diff --git a/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
similarity index 99%
rename from services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
rename to packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
index f952bce..6b0f1de 100644
--- a/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
@@ -87,7 +87,6 @@
     private static final int EVENT_MAYBE_RUN_PROVISIONING = 3;
     private static final int EVENT_GET_ENTITLEMENT_VALUE = 4;
 
-
     // The ArraySet contains enabled downstream types, ex:
     // {@link ConnectivityManager.TETHERING_WIFI}
     // {@link ConnectivityManager.TETHERING_USB}
@@ -112,7 +111,6 @@
 
     public EntitlementManager(Context ctx, StateMachine tetherMasterSM, SharedLog log,
             int permissionChangeMessageCode, MockableSystemProperties systemProperties) {
-
         mContext = ctx;
         mLog = log.forSubComponent(TAG);
         mCurrentTethers = new ArraySet<Integer>();
@@ -138,7 +136,7 @@
         /**
          * Ui entitlement check fails in |downstream|.
          *
-         * @param downstream  tethering type from ConnectivityManager.TETHERING_{@code *}.
+         * @param downstream tethering type from ConnectivityManager.TETHERING_{@code *}.
          */
         void onUiEntitlementFailed(int downstream);
     }
@@ -662,7 +660,6 @@
 
     private void handleGetLatestTetheringEntitlementValue(int downstream, ResultReceiver receiver,
             boolean showEntitlementUi) {
-
         final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
         if (!isTetherProvisioningRequired(config)) {
             receiver.send(TETHER_ERROR_NO_ERROR, null);
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java
similarity index 97%
rename from services/core/java/com/android/server/connectivity/tethering/OffloadController.java
rename to packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java
index a3c2998..16734d8 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java
@@ -36,8 +36,8 @@
 import android.net.util.IpUtils;
 import android.net.util.SharedLog;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.INetworkManagementService;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.provider.Settings;
@@ -60,7 +60,6 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
 
 /**
  * A class to encapsulate the business logic of programming the tethering
@@ -74,7 +73,7 @@
     private static final String ANYIP = "0.0.0.0";
     private static final ForwardedStats EMPTY_STATS = new ForwardedStats();
 
-    private static enum UpdateType { IF_NEEDED, FORCE };
+    private enum UpdateType { IF_NEEDED, FORCE };
 
     private final Handler mHandler;
     private final OffloadHardwareInterface mHwInterface;
@@ -128,6 +127,7 @@
         }
     }
 
+    /** Start hardware offload. */
     public boolean start() {
         if (started()) return true;
 
@@ -235,6 +235,7 @@
         return isStarted;
     }
 
+    /** Stop hardware offload. */
     public void stop() {
         // Completely stops tethering offload. After this method is called, it is no longer safe to
         // call any HAL method, no callbacks from the hardware will be delivered, and any in-flight
@@ -258,7 +259,9 @@
             // getTetherStats() is the only function in OffloadController that can be called from
             // a different thread. Do not attempt to update stats by querying the offload HAL
             // synchronously from a different thread than our Handler thread. http://b/64771555.
-            Runnable updateStats = () -> { updateStatsForCurrentUpstream(); };
+            Runnable updateStats = () -> {
+                updateStatsForCurrentUpstream();
+            };
             if (Looper.myLooper() == mHandler.getLooper()) {
                 updateStats.run();
             } else {
@@ -358,6 +361,7 @@
         }
     }
 
+    /** Set current tethering upstream LinkProperties. */
     public void setUpstreamLinkProperties(LinkProperties lp) {
         if (!started() || Objects.equals(mUpstreamLinkProperties, lp)) return;
 
@@ -376,6 +380,7 @@
         pushUpstreamParameters(prevUpstream);
     }
 
+    /** Set local prefixes. */
     public void setLocalPrefixes(Set<IpPrefix> localPrefixes) {
         mExemptPrefixes = localPrefixes;
 
@@ -383,6 +388,7 @@
         computeAndPushLocalPrefixes(UpdateType.IF_NEEDED);
     }
 
+    /** Update current downstream LinkProperties. */
     public void notifyDownstreamLinkProperties(LinkProperties lp) {
         final String ifname = lp.getInterfaceName();
         final LinkProperties oldLp = mDownstreams.put(ifname, new LinkProperties(lp));
@@ -421,6 +427,7 @@
         }
     }
 
+    /** Remove downstream interface from offload hardware. */
     public void removeDownstreamInterface(String ifname) {
         final LinkProperties lp = mDownstreams.remove(ifname);
         if (lp == null) return;
@@ -481,7 +488,7 @@
                 iface, v4addr, v4gateway, (v6gateways.isEmpty() ? null : v6gateways));
 
         if (!success) {
-           return success;
+            return success;
         }
 
         // Update stats after we've told the hardware to change routing so we don't miss packets.
@@ -545,6 +552,7 @@
         return false;
     }
 
+    /** Dump information. */
     public void dump(IndentingPrintWriter pw) {
         if (isOffloadDisabled()) {
             pw.println("Offload disabled");
@@ -630,7 +638,7 @@
             if (ip instanceof Inet4Address) {
                 return (Inet4Address) ip;
             }
-        } catch (IllegalArgumentException iae) {}
+        } catch (IllegalArgumentException iae) { }
         return null;
     }
 
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
similarity index 81%
rename from services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
rename to packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
index 207f867..01339a4 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
@@ -23,9 +23,9 @@
 import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
 import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
 import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
+import android.net.util.SharedLog;
 import android.os.Handler;
 import android.os.RemoteException;
-import android.net.util.SharedLog;
 import android.system.OsConstants;
 
 import java.util.ArrayList;
@@ -55,18 +55,34 @@
     private TetheringOffloadCallback mTetheringOffloadCallback;
     private ControlCallback mControlCallback;
 
+    /** The callback to notify status of offload management process. */
     public static class ControlCallback {
+        /** Offload started. */
         public void onStarted() {}
+        /**
+         * Offload stopped because an error has occurred in lower layer.
+         */
         public void onStoppedError() {}
+        /**
+         * Offload stopped because the device has moved to a bearer on which hardware offload is
+         * not supported. Subsequent calls to setUpstreamParameters and add/removeDownstream will
+         * likely fail and cannot be presumed to be saved inside of the hardware management process.
+         * Upon receiving #onSupportAvailable(), the caller should reprogram the hardware to begin
+         * offload again.
+         */
         public void onStoppedUnsupported() {}
+        /** Indicate that offload is able to proivde support for this time. */
         public void onSupportAvailable() {}
+        /** Offload stopped because of usage limit reached. */
         public void onStoppedLimitReached() {}
 
+        /** Indicate to update NAT timeout. */
         public void onNatTimeoutUpdate(int proto,
                                        String srcAddr, int srcPort,
                                        String dstAddr, int dstPort) {}
     }
 
+    /** The object which records Tx/Rx forwarded bytes. */
     public static class ForwardedStats {
         public long rxBytes;
         public long txBytes;
@@ -76,11 +92,13 @@
             txBytes = 0;
         }
 
+        /** Add Tx/Rx bytes. */
         public void add(ForwardedStats other) {
             rxBytes += other.rxBytes;
             txBytes += other.txBytes;
         }
 
+        /** Returns the string representation of this object. */
         public String toString() {
             return String.format("rx:%s tx:%s", rxBytes, txBytes);
         }
@@ -91,14 +109,17 @@
         mLog = log.forSubComponent(TAG);
     }
 
+    /** Get default value indicating whether offload is supported. */
     public int getDefaultTetherOffloadDisabled() {
         return DEFAULT_TETHER_OFFLOAD_DISABLED;
     }
 
+    /** Configure offload management process. */
     public boolean initOffloadConfig() {
         return configOffload();
     }
 
+    /** Initialize the tethering offload HAL. */
     public boolean initOffloadControl(ControlCallback controlCb) {
         mControlCallback = controlCb;
 
@@ -125,8 +146,8 @@
             mOffloadControl.initOffload(
                     mTetheringOffloadCallback,
                     (boolean success, String errMsg) -> {
-                        results.success = success;
-                        results.errMsg = errMsg;
+                        results.mSuccess = success;
+                        results.mErrMsg = errMsg;
                     });
         } catch (RemoteException e) {
             record(logmsg, e);
@@ -134,9 +155,10 @@
         }
 
         record(logmsg, results);
-        return results.success;
+        return results.mSuccess;
     }
 
+    /** Stop IOffloadControl. */
     public void stopOffloadControl() {
         if (mOffloadControl != null) {
             try {
@@ -154,6 +176,7 @@
         mLog.log("stopOffloadControl()");
     }
 
+    /** Get Tx/Rx usage from last query. */
     public ForwardedStats getForwardedStats(String upstream) {
         final String logmsg = String.format("getForwardedStats(%s)",  upstream);
 
@@ -174,6 +197,7 @@
         return stats;
     }
 
+    /** Set local prefixes to offload management process. */
     public boolean setLocalPrefixes(ArrayList<String> localPrefixes) {
         final String logmsg = String.format("setLocalPrefixes([%s])",
                 String.join(",", localPrefixes));
@@ -182,8 +206,8 @@
         try {
             mOffloadControl.setLocalPrefixes(localPrefixes,
                     (boolean success, String errMsg) -> {
-                        results.success = success;
-                        results.errMsg = errMsg;
+                        results.mSuccess = success;
+                        results.mErrMsg = errMsg;
                     });
         } catch (RemoteException e) {
             record(logmsg, e);
@@ -191,9 +215,10 @@
         }
 
         record(logmsg, results);
-        return results.success;
+        return results.mSuccess;
     }
 
+    /** Set data limit value to offload management process. */
     public boolean setDataLimit(String iface, long limit) {
 
         final String logmsg = String.format("setDataLimit(%s, %d)", iface, limit);
@@ -203,8 +228,8 @@
             mOffloadControl.setDataLimit(
                     iface, limit,
                     (boolean success, String errMsg) -> {
-                        results.success = success;
-                        results.errMsg = errMsg;
+                        results.mSuccess = success;
+                        results.mErrMsg = errMsg;
                     });
         } catch (RemoteException e) {
             record(logmsg, e);
@@ -212,9 +237,10 @@
         }
 
         record(logmsg, results);
-        return results.success;
+        return results.mSuccess;
     }
 
+    /** Set upstream parameters to offload management process. */
     public boolean setUpstreamParameters(
             String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) {
         iface = (iface != null) ? iface : NO_INTERFACE_NAME;
@@ -230,8 +256,8 @@
             mOffloadControl.setUpstreamParameters(
                     iface, v4addr, v4gateway, v6gws,
                     (boolean success, String errMsg) -> {
-                        results.success = success;
-                        results.errMsg = errMsg;
+                        results.mSuccess = success;
+                        results.mErrMsg = errMsg;
                     });
         } catch (RemoteException e) {
             record(logmsg, e);
@@ -239,9 +265,10 @@
         }
 
         record(logmsg, results);
-        return results.success;
+        return results.mSuccess;
     }
 
+    /** Add downstream prefix to offload management process. */
     public boolean addDownstreamPrefix(String ifname, String prefix) {
         final String logmsg = String.format("addDownstreamPrefix(%s, %s)", ifname, prefix);
 
@@ -249,8 +276,8 @@
         try {
             mOffloadControl.addDownstream(ifname, prefix,
                     (boolean success, String errMsg) -> {
-                        results.success = success;
-                        results.errMsg = errMsg;
+                        results.mSuccess = success;
+                        results.mErrMsg = errMsg;
                     });
         } catch (RemoteException e) {
             record(logmsg, e);
@@ -258,9 +285,10 @@
         }
 
         record(logmsg, results);
-        return results.success;
+        return results.mSuccess;
     }
 
+    /** Remove downstream prefix from offload management process. */
     public boolean removeDownstreamPrefix(String ifname, String prefix) {
         final String logmsg = String.format("removeDownstreamPrefix(%s, %s)", ifname, prefix);
 
@@ -268,8 +296,8 @@
         try {
             mOffloadControl.removeDownstream(ifname, prefix,
                     (boolean success, String errMsg) -> {
-                        results.success = success;
-                        results.errMsg = errMsg;
+                        results.mSuccess = success;
+                        results.mErrMsg = errMsg;
                     });
         } catch (RemoteException e) {
             record(logmsg, e);
@@ -277,7 +305,7 @@
         }
 
         record(logmsg, results);
-        return results.success;
+        return results.mSuccess;
     }
 
     private void record(String msg, Throwable t) {
@@ -286,7 +314,7 @@
 
     private void record(String msg, CbResults results) {
         final String logmsg = msg + YIELDS + results;
-        if (!results.success) {
+        if (!results.mSuccess) {
             mLog.e(logmsg);
         } else {
             mLog.log(logmsg);
@@ -298,7 +326,7 @@
         public final ControlCallback controlCb;
         public final SharedLog log;
 
-        public TetheringOffloadCallback(Handler h, ControlCallback cb, SharedLog sharedLog) {
+        TetheringOffloadCallback(Handler h, ControlCallback cb, SharedLog sharedLog) {
             handler = h;
             controlCb = cb;
             log = sharedLog;
@@ -332,7 +360,7 @@
         @Override
         public void updateTimeout(NatTimeoutUpdate params) {
             handler.post(() -> {
-                    controlCb.onNatTimeoutUpdate(
+                controlCb.onNatTimeoutUpdate(
                         networkProtocolToOsConstant(params.proto),
                         params.src.addr, uint16(params.src.port),
                         params.dst.addr, uint16(params.dst.port));
@@ -352,15 +380,15 @@
     }
 
     private static class CbResults {
-        boolean success;
-        String errMsg;
+        boolean mSuccess;
+        String mErrMsg;
 
         @Override
         public String toString() {
-            if (success) {
+            if (mSuccess) {
                 return "ok";
             } else {
-                return "fail: " + errMsg;
+                return "fail: " + mErrMsg;
             }
         }
     }
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
similarity index 96%
rename from services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
rename to packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
index a1b94ca..7709727 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -82,7 +82,7 @@
         "192.168.48.2", "192.168.48.254", "192.168.49.2", "192.168.49.254",
     };
 
-    private final String[] DEFAULT_IPV4_DNS = {"8.8.4.4", "8.8.8.8"};
+    private static final String[] DEFAULT_IPV4_DNS = {"8.8.4.4", "8.8.8.8"};
 
     public final String[] tetherableUsbRegexs;
     public final String[] tetherableWifiRegexs;
@@ -133,10 +133,12 @@
         configLog.log(toString());
     }
 
+    /** Check whether input interface belong to usb.*/
     public boolean isUsb(String iface) {
         return matchesDownstreamRegexs(iface, tetherableUsbRegexs);
     }
 
+    /** Check whether input interface belong to wifi.*/
     public boolean isWifi(String iface) {
         return matchesDownstreamRegexs(iface, tetherableWifiRegexs);
     }
@@ -146,18 +148,22 @@
         return matchesDownstreamRegexs(iface, tetherableWifiP2pRegexs);
     }
 
+    /** Check whether using legacy mode for wifi P2P. */
     public boolean isWifiP2pLegacyTetheringMode() {
         return (tetherableWifiP2pRegexs == null || tetherableWifiP2pRegexs.length == 0);
     }
 
+    /** Check whether input interface belong to bluetooth.*/
     public boolean isBluetooth(String iface) {
         return matchesDownstreamRegexs(iface, tetherableBluetoothRegexs);
     }
 
+    /** Check whether no ui entitlement application is available.*/
     public boolean hasMobileHotspotProvisionApp() {
         return !TextUtils.isEmpty(provisioningAppNoUi);
     }
 
+    /** Does the dumping.*/
     public void dump(PrintWriter pw) {
         pw.print("subId: ");
         pw.println(subId);
@@ -186,6 +192,7 @@
         pw.println(enableLegacyDhcpServer);
     }
 
+    /** Returns the string representation of this object.*/
     public String toString() {
         final StringJoiner sj = new StringJoiner(" ");
         sj.add(String.format("subId:%d", subId));
@@ -210,7 +217,7 @@
 
         if (values != null) {
             final StringJoiner sj = new StringJoiner(", ", "[", "]");
-            for (String value : values) { sj.add(value); }
+            for (String value : values) sj.add(value);
             pw.print(sj.toString());
         } else {
             pw.print("null");
diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
similarity index 93%
rename from services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
rename to packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
index 3a9e21f..9769596 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -146,6 +146,7 @@
         }
     }
 
+    /** Listen all networks. */
     public void startObserveAllNetworks() {
         stop();
 
@@ -155,6 +156,13 @@
         cm().registerNetworkCallback(listenAllRequest, mListenAllCallback, mHandler);
     }
 
+    /**
+     * Stop tracking candidate tethering upstreams and release mobile network request.
+     * Note: this function is used when tethering is stopped because tethering do not need to
+     * choose upstream anymore. But it would not stop default network tracking because
+     * EntitlementManager may need to know default network to decide whether to request entitlement
+     * check even tethering is not active yet.
+     */
     public void stop() {
         releaseMobileNetworkRequest();
 
@@ -165,6 +173,7 @@
         mNetworkMap.clear();
     }
 
+    /** Setup or teardown DUN connection according to |dunRequired|. */
     public void updateMobileRequiresDun(boolean dunRequired) {
         final boolean valueChanged = (mDunRequired != dunRequired);
         mDunRequired = dunRequired;
@@ -174,10 +183,12 @@
         }
     }
 
+    /** Whether mobile network is requested. */
     public boolean mobileNetworkRequested() {
         return (mMobileNetworkCallback != null);
     }
 
+    /** Request mobile network if mobile upstream is permitted. */
     public void registerMobileNetworkRequest() {
         if (!isCellularUpstreamPermitted()) {
             mLog.i("registerMobileNetworkRequest() is not permitted");
@@ -209,6 +220,7 @@
         cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, legacyType, mHandler);
     }
 
+    /** Release mobile network request. */
     public void releaseMobileNetworkRequest() {
         if (mMobileNetworkCallback == null) return;
 
@@ -221,6 +233,9 @@
     // becomes available and useful we (a) file a request to keep it up as
     // necessary and (b) change all upstream tracking state accordingly (by
     // passing LinkProperties up to Tethering).
+    /**
+     * Select the first available network from |perferredTypes|.
+     */
     public NetworkState selectPreferredUpstreamType(Iterable<Integer> preferredTypes) {
         final TypeStatePair typeStatePair = findFirstAvailableUpstreamByType(
                 mNetworkMap.values(), preferredTypes, isCellularUpstreamPermitted());
@@ -254,7 +269,11 @@
         return typeStatePair.ns;
     }
 
-    // Returns null if no current upstream available.
+    /**
+     * Get current preferred upstream network. If default network is cellular and DUN is required,
+     * preferred upstream would be DUN otherwise preferred upstream is the same as default network.
+     * Returns null if no current upstream is available.
+     */
     public NetworkState getCurrentPreferredUpstream() {
         final NetworkState dfltState = (mDefaultInternetNetwork != null)
                 ? mNetworkMap.get(mDefaultInternetNetwork)
@@ -270,10 +289,12 @@
         return findFirstDunNetwork(mNetworkMap.values());
     }
 
+    /** Tell UpstreamNetworkMonitor which network is the current upstream of tethering. */
     public void setCurrentUpstream(Network upstream) {
         mTetheringUpstreamNetwork = upstream;
     }
 
+    /** Return local prefixes. */
     public Set<IpPrefix> getLocalPrefixes() {
         return (Set<IpPrefix>) mLocalPrefixes.clone();
     }
@@ -501,8 +522,8 @@
             try {
                 nc = ConnectivityManager.networkCapabilitiesForType(type);
             } catch (IllegalArgumentException iae) {
-                Log.e(TAG, "No NetworkCapabilities mapping for legacy type: " +
-                       ConnectivityManager.getNetworkTypeName(type));
+                Log.e(TAG, "No NetworkCapabilities mapping for legacy type: "
+                        + ConnectivityManager.getNetworkTypeName(type));
                 continue;
             }
             if (!isCellularUpstreamPermitted && isCellular(nc)) {
@@ -547,18 +568,18 @@
     }
 
     private static boolean isCellular(NetworkCapabilities nc) {
-        return (nc != null) && nc.hasTransport(TRANSPORT_CELLULAR) &&
-               nc.hasCapability(NET_CAPABILITY_NOT_VPN);
+        return (nc != null) && nc.hasTransport(TRANSPORT_CELLULAR)
+               && nc.hasCapability(NET_CAPABILITY_NOT_VPN);
     }
 
     private static boolean hasCapability(NetworkState ns, int netCap) {
-        return (ns != null) && (ns.networkCapabilities != null) &&
-               ns.networkCapabilities.hasCapability(netCap);
+        return (ns != null) && (ns.networkCapabilities != null)
+               && ns.networkCapabilities.hasCapability(netCap);
     }
 
     private static boolean isNetworkUsableAndNotCellular(NetworkState ns) {
-        return (ns != null) && (ns.networkCapabilities != null) && (ns.linkProperties != null) &&
-               !isCellular(ns.networkCapabilities);
+        return (ns != null) && (ns.networkCapabilities != null) && (ns.linkProperties != null)
+               && !isCellular(ns.networkCapabilities);
     }
 
     private static NetworkState findFirstDunNetwork(Iterable<NetworkState> netStates) {
diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp
new file mode 100644
index 0000000..363be18
--- /dev/null
+++ b/packages/Tethering/tests/unit/Android.bp
@@ -0,0 +1,57 @@
+//
+// 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.
+//
+
+android_test {
+    name: "TetheringTests",
+    certificate: "platform",
+    srcs: [
+        ":servicescore-tethering-src",
+        "src/**/*.java",
+    ],
+    test_suites: ["device-tests"],
+    static_libs: [
+        "androidx.test.rules",
+        "frameworks-base-testutils",
+        "net-tests-utils",
+        "mockito-target-extended-minus-junit4",
+        "TetheringApiCurrentLib",
+        "testables",
+    ],
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+        "android.test.mock",
+    ],
+    jni_libs: [
+        // For mockito extended
+        "libdexmakerjvmtiagent",
+        "libstaticjvmtiagent",
+    ],
+}
+
+// This group would be removed when tethering migration is done.
+filegroup {
+    name: "tethering-tests-src",
+    srcs: [
+        "src/com/android/server/connectivity/tethering/EntitlementManagerTest.java",
+        "src/com/android/server/connectivity/tethering/OffloadControllerTest.java",
+        "src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java",
+        "src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java",
+        "src/android/net/dhcp/DhcpServingParamsParcelExtTest.java",
+        "src/android/net/ip/IpServerTest.java",
+        "src/android/net/util/InterfaceSetTest.java",
+    ],
+}
diff --git a/packages/Tethering/tests/unit/AndroidManifest.xml b/packages/Tethering/tests/unit/AndroidManifest.xml
new file mode 100644
index 0000000..049ff6d
--- /dev/null
+++ b/packages/Tethering/tests/unit/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.tethering.tests.unit">
+
+    <application android:debuggable="true">
+        <uses-library android:name="android.test.runner" />
+    </application>
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.tethering.tests.unit"
+        android:label="Tethering service tests">
+    </instrumentation>
+</manifest>
diff --git a/tests/net/java/android/net/dhcp/DhcpServingParamsParcelExtTest.java b/packages/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java
similarity index 100%
rename from tests/net/java/android/net/dhcp/DhcpServingParamsParcelExtTest.java
rename to packages/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java
diff --git a/tests/net/java/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
similarity index 99%
rename from tests/net/java/android/net/ip/IpServerTest.java
rename to packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index b6ccebb..4358cd6 100644
--- a/tests/net/java/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -183,7 +183,7 @@
     @Test
     public void shouldDoNothingUntilRequested() throws Exception {
         initStateMachine(TETHERING_BLUETOOTH);
-        final int [] NOOP_COMMANDS = {
+        final int [] noOp_commands = {
             IpServer.CMD_TETHER_UNREQUESTED,
             IpServer.CMD_IP_FORWARDING_ENABLE_ERROR,
             IpServer.CMD_IP_FORWARDING_DISABLE_ERROR,
@@ -192,7 +192,7 @@
             IpServer.CMD_SET_DNS_FORWARDERS_ERROR,
             IpServer.CMD_TETHER_CONNECTION_CHANGED
         };
-        for (int command : NOOP_COMMANDS) {
+        for (int command : noOp_commands) {
             // None of these commands should trigger us to request action from
             // the rest of the system.
             dispatchCommand(command);
diff --git a/tests/net/java/android/net/util/InterfaceSetTest.java b/packages/Tethering/tests/unit/src/android/net/util/InterfaceSetTest.java
similarity index 100%
rename from tests/net/java/android/net/util/InterfaceSetTest.java
rename to packages/Tethering/tests/unit/src/android/net/util/InterfaceSetTest.java
diff --git a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
similarity index 100%
rename from tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
rename to packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
diff --git a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java
similarity index 98%
rename from tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
rename to packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java
index 9931aec..8574f54 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java
@@ -26,10 +26,10 @@
 
 import static com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats;
 import static com.android.testutils.MiscAssertsKt.assertContainsAll;
+import static com.android.testutils.MiscAssertsKt.assertThrows;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.anyObject;
@@ -148,10 +148,8 @@
     public void testNoSettingsValueDefaultDisabledDoesNotStart() throws Exception {
         setupFunctioningHardwareInterface();
         when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(1);
-        try {
-            Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED);
-            fail();
-        } catch (SettingNotFoundException expected) {}
+        assertThrows(SettingNotFoundException.class, () ->
+                Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED));
 
         final OffloadController offload = makeOffloadController();
         offload.start();
@@ -168,10 +166,8 @@
     public void testNoSettingsValueDefaultEnabledDoesStart() throws Exception {
         setupFunctioningHardwareInterface();
         when(mHardware.getDefaultTetherOffloadDisabled()).thenReturn(0);
-        try {
-            Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED);
-            fail();
-        } catch (SettingNotFoundException expected) {}
+        assertThrows(SettingNotFoundException.class, () ->
+                Settings.Global.getInt(mContentResolver, TETHER_OFFLOAD_DISABLED));
 
         final OffloadController offload = makeOffloadController();
         offload.start();
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
similarity index 91%
rename from tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
rename to packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
index e282963..9f9221f 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
@@ -24,7 +24,12 @@
 import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER;
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
+import static com.android.internal.R.array.config_mobile_hotspot_provision_app;
+import static com.android.internal.R.array.config_tether_bluetooth_regexs;
+import static com.android.internal.R.array.config_tether_dhcp_range;
 import static com.android.internal.R.array.config_tether_upstream_types;
+import static com.android.internal.R.array.config_tether_usb_regexs;
+import static com.android.internal.R.array.config_tether_wifi_regexs;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -86,7 +91,9 @@
         }
 
         @Override
-        public Resources getResources() { return mResources; }
+        public Resources getResources() {
+            return mResources;
+        }
 
         @Override
         public Object getSystemService(String name) {
@@ -105,17 +112,13 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range))
-                .thenReturn(new String[0]);
-        when(mResources.getStringArray(com.android.internal.R.array.config_tether_usb_regexs))
-                .thenReturn(new String[0]);
-        when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs))
+        when(mResources.getStringArray(config_tether_dhcp_range)).thenReturn(new String[0]);
+        when(mResources.getStringArray(config_tether_usb_regexs)).thenReturn(new String[0]);
+        when(mResources.getStringArray(config_tether_wifi_regexs))
                 .thenReturn(new String[]{ "test_wlan\\d" });
-        when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs))
-                .thenReturn(new String[0]);
+        when(mResources.getStringArray(config_tether_bluetooth_regexs)).thenReturn(new String[0]);
         when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(new int[0]);
-        when(mResources.getStringArray(
-                com.android.internal.R.array.config_mobile_hotspot_provision_app))
+        when(mResources.getStringArray(config_mobile_hotspot_provision_app))
                 .thenReturn(new String[0]);
         mContentResolver = new MockContentResolver();
         mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
@@ -297,19 +300,16 @@
 
     private void setUpResourceForSubId() {
         when(mResourcesForSubId.getStringArray(
-                com.android.internal.R.array.config_tether_dhcp_range)).thenReturn(new String[0]);
+                config_tether_dhcp_range)).thenReturn(new String[0]);
         when(mResourcesForSubId.getStringArray(
-                com.android.internal.R.array.config_tether_usb_regexs)).thenReturn(new String[0]);
+                config_tether_usb_regexs)).thenReturn(new String[0]);
         when(mResourcesForSubId.getStringArray(
-                com.android.internal.R.array.config_tether_wifi_regexs))
-                .thenReturn(new String[]{ "test_wlan\\d" });
+                config_tether_wifi_regexs)).thenReturn(new String[]{ "test_wlan\\d" });
         when(mResourcesForSubId.getStringArray(
-                com.android.internal.R.array.config_tether_bluetooth_regexs))
-                .thenReturn(new String[0]);
+                config_tether_bluetooth_regexs)).thenReturn(new String[0]);
         when(mResourcesForSubId.getIntArray(config_tether_upstream_types)).thenReturn(new int[0]);
         when(mResourcesForSubId.getStringArray(
-                com.android.internal.R.array.config_mobile_hotspot_provision_app))
-                .thenReturn(PROVISIONING_APP_NAME);
+                config_mobile_hotspot_provision_app)).thenReturn(PROVISIONING_APP_NAME);
     }
 
 }
diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
similarity index 94%
rename from tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
rename to packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
index 0d276cb..c028d6d 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -87,7 +87,7 @@
 
     // Actual contents of the request don't matter for this test. The lack of
     // any specific TRANSPORT_* is sufficient to identify this request.
-    private static final NetworkRequest mDefaultRequest = new NetworkRequest.Builder().build();
+    private static final NetworkRequest sDefaultRequest = new NetworkRequest.Builder().build();
 
     @Mock private Context mContext;
     @Mock private EntitlementManager mEntitleMgr;
@@ -140,7 +140,7 @@
     @Test
     public void testDefaultNetworkIsTracked() throws Exception {
         assertTrue(mCM.hasNoCallbacks());
-        mUNM.startTrackDefaultNetwork(mDefaultRequest, mEntitleMgr);
+        mUNM.startTrackDefaultNetwork(sDefaultRequest, mEntitleMgr);
 
         mUNM.startObserveAllNetworks();
         assertEquals(1, mCM.trackingDefault.size());
@@ -153,7 +153,7 @@
     public void testListensForAllNetworks() throws Exception {
         assertTrue(mCM.listening.isEmpty());
 
-        mUNM.startTrackDefaultNetwork(mDefaultRequest, mEntitleMgr);
+        mUNM.startTrackDefaultNetwork(sDefaultRequest, mEntitleMgr);
         mUNM.startObserveAllNetworks();
         assertFalse(mCM.listening.isEmpty());
         assertTrue(mCM.isListeningForAll());
@@ -164,9 +164,9 @@
 
     @Test
     public void testCallbacksRegistered() {
-        mUNM.startTrackDefaultNetwork(mDefaultRequest, mEntitleMgr);
+        mUNM.startTrackDefaultNetwork(sDefaultRequest, mEntitleMgr);
         verify(mCM, times(1)).requestNetwork(
-                eq(mDefaultRequest), any(NetworkCallback.class), any(Handler.class));
+                eq(sDefaultRequest), any(NetworkCallback.class), any(Handler.class));
         mUNM.startObserveAllNetworks();
         verify(mCM, times(1)).registerNetworkCallback(
                 any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
@@ -191,7 +191,7 @@
         mUNM.registerMobileNetworkRequest();
         assertTrue(mUNM.mobileNetworkRequested());
         assertUpstreamTypeRequested(TYPE_MOBILE_HIPRI);
-        assertFalse(mCM.isDunRequested());
+        assertFalse(isDunRequested());
 
         mUNM.stop();
         assertFalse(mUNM.mobileNetworkRequested());
@@ -217,7 +217,7 @@
 
         assertTrue(mUNM.mobileNetworkRequested());
         assertUpstreamTypeRequested(TYPE_MOBILE_DUN);
-        assertTrue(mCM.isDunRequested());
+        assertTrue(isDunRequested());
 
         // Try a few things that must not result in any state change.
         mUNM.registerMobileNetworkRequest();
@@ -226,7 +226,7 @@
 
         assertTrue(mUNM.mobileNetworkRequested());
         assertUpstreamTypeRequested(TYPE_MOBILE_DUN);
-        assertTrue(mCM.isDunRequested());
+        assertTrue(isDunRequested());
 
         mUNM.stop();
         verify(mCM, times(2)).unregisterNetworkCallback(any(NetworkCallback.class));
@@ -250,7 +250,7 @@
         mUNM.registerMobileNetworkRequest();
         assertTrue(mUNM.mobileNetworkRequested());
         assertUpstreamTypeRequested(TYPE_MOBILE_DUN);
-        assertTrue(mCM.isDunRequested());
+        assertTrue(isDunRequested());
 
         mUNM.stop();
         assertFalse(mUNM.mobileNetworkRequested());
@@ -266,17 +266,17 @@
         mUNM.registerMobileNetworkRequest();
         assertTrue(mUNM.mobileNetworkRequested());
         assertUpstreamTypeRequested(TYPE_MOBILE_HIPRI);
-        assertFalse(mCM.isDunRequested());
+        assertFalse(isDunRequested());
         mUNM.updateMobileRequiresDun(true);
         assertTrue(mUNM.mobileNetworkRequested());
         assertUpstreamTypeRequested(TYPE_MOBILE_DUN);
-        assertTrue(mCM.isDunRequested());
+        assertTrue(isDunRequested());
 
         // Test going from DUN to no-DUN correctly re-registers callbacks.
         mUNM.updateMobileRequiresDun(false);
         assertTrue(mUNM.mobileNetworkRequested());
         assertUpstreamTypeRequested(TYPE_MOBILE_HIPRI);
-        assertFalse(mCM.isDunRequested());
+        assertFalse(isDunRequested());
 
         mUNM.stop();
         assertFalse(mUNM.mobileNetworkRequested());
@@ -287,7 +287,7 @@
         final Collection<Integer> preferredTypes = new ArrayList<>();
         preferredTypes.add(TYPE_WIFI);
 
-        mUNM.startTrackDefaultNetwork(mDefaultRequest, mEntitleMgr);
+        mUNM.startTrackDefaultNetwork(sDefaultRequest, mEntitleMgr);
         mUNM.startObserveAllNetworks();
         // There are no networks, so there is nothing to select.
         assertSatisfiesLegacyType(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes));
@@ -369,7 +369,7 @@
 
     @Test
     public void testGetCurrentPreferredUpstream() throws Exception {
-        mUNM.startTrackDefaultNetwork(mDefaultRequest, mEntitleMgr);
+        mUNM.startTrackDefaultNetwork(sDefaultRequest, mEntitleMgr);
         mUNM.startObserveAllNetworks();
         mUNM.updateMobileRequiresDun(false);
 
@@ -418,7 +418,7 @@
 
     @Test
     public void testLocalPrefixes() throws Exception {
-        mUNM.startTrackDefaultNetwork(mDefaultRequest, mEntitleMgr);
+        mUNM.startTrackDefaultNetwork(sDefaultRequest, mEntitleMgr);
         mUNM.startObserveAllNetworks();
 
         // [0] Test minimum set of local prefixes.
@@ -431,13 +431,13 @@
         final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI);
         final LinkProperties wifiLp = wifiAgent.linkProperties;
         wifiLp.setInterfaceName("wlan0");
-        final String[] WIFI_ADDRS = {
+        final String[] wifi_addrs = {
                 "fe80::827a:bfff:fe6f:374d", "100.112.103.18",
                 "2001:db8:4:fd00:827a:bfff:fe6f:374d",
                 "2001:db8:4:fd00:6dea:325a:fdae:4ef4",
                 "fd6a:a640:60bf:e985::123",  // ULA address for good measure.
         };
-        for (String addrStr : WIFI_ADDRS) {
+        for (String addrStr : wifi_addrs) {
             final String cidr = addrStr.contains(":") ? "/64" : "/20";
             wifiLp.addLinkAddress(new LinkAddress(addrStr + cidr));
         }
@@ -458,10 +458,10 @@
         final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
         final LinkProperties cellLp = cellAgent.linkProperties;
         cellLp.setInterfaceName("rmnet_data0");
-        final String[] CELL_ADDRS = {
+        final String[] cell_addrs = {
                 "10.102.211.48", "2001:db8:0:1:b50e:70d9:10c9:433d",
         };
-        for (String addrStr : CELL_ADDRS) {
+        for (String addrStr : cell_addrs) {
             final String cidr = addrStr.contains(":") ? "/64" : "/27";
             cellLp.addLinkAddress(new LinkAddress(addrStr + cidr));
         }
@@ -481,10 +481,10 @@
         dunAgent.networkCapabilities.removeCapability(NET_CAPABILITY_INTERNET);
         final LinkProperties dunLp = dunAgent.linkProperties;
         dunLp.setInterfaceName("rmnet_data1");
-        final String[] DUN_ADDRS = {
+        final String[] dun_addrs = {
                 "192.0.2.48", "2001:db8:1:2:b50e:70d9:10c9:433d",
         };
-        for (String addrStr : DUN_ADDRS) {
+        for (String addrStr : dun_addrs) {
             final String cidr = addrStr.contains(":") ? "/64" : "/27";
             dunLp.addLinkAddress(new LinkAddress(addrStr + cidr));
         }
@@ -525,7 +525,7 @@
         // Mobile has higher pirority than wifi.
         preferredTypes.add(TYPE_MOBILE_HIPRI);
         preferredTypes.add(TYPE_WIFI);
-        mUNM.startTrackDefaultNetwork(mDefaultRequest, mEntitleMgr);
+        mUNM.startTrackDefaultNetwork(sDefaultRequest, mEntitleMgr);
         mUNM.startObserveAllNetworks();
         // Setup wifi and make wifi as default network.
         final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI);
@@ -556,6 +556,15 @@
                 mCM.legacyTypeMap.values().iterator().next());
     }
 
+    private boolean isDunRequested() {
+        for (NetworkRequest req : mCM.requested.values()) {
+            if (req.networkCapabilities.hasCapability(NET_CAPABILITY_DUN)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     public static class TestConnectivityManager extends ConnectivityManager {
         public Map<NetworkCallback, Handler> allCallbacks = new HashMap<>();
         public Set<NetworkCallback> trackingDefault = new HashSet<>();
@@ -598,17 +607,10 @@
             return false;
         }
 
-        boolean isDunRequested() {
-            for (NetworkRequest req : requested.values()) {
-                if (req.networkCapabilities.hasCapability(NET_CAPABILITY_DUN)) {
-                    return true;
-                }
-            }
-            return false;
+        int getNetworkId() {
+            return ++mNetworkId;
         }
 
-        int getNetworkId() { return ++mNetworkId; }
-
         void makeDefaultNetwork(TestNetworkAgent agent) {
             if (Objects.equals(defaultNetwork, agent)) return;
 
@@ -630,7 +632,7 @@
         public void requestNetwork(NetworkRequest req, NetworkCallback cb, Handler h) {
             assertFalse(allCallbacks.containsKey(cb));
             allCallbacks.put(cb, h);
-            if (mDefaultRequest.equals(req)) {
+            if (sDefaultRequest.equals(req)) {
                 assertFalse(trackingDefault.contains(cb));
                 trackingDefault.add(cb);
             } else {
@@ -749,9 +751,13 @@
         private final State mLoggingState = new LoggingState();
 
         class LoggingState extends State {
-            @Override public void enter() { messages.clear(); }
+            @Override public void enter() {
+                messages.clear();
+            }
 
-            @Override public void exit() { messages.clear(); }
+            @Override public void exit() {
+                messages.clear();
+            }
 
             @Override public boolean processMessage(Message msg) {
                 messages.add(msg);
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index 5d6d1c9..5712566 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -253,6 +253,8 @@
     NOTE_NETWORK_LOGGED_IN = 744;
     // A partial connectivity network was detected during network validation
     NOTE_NETWORK_PARTIAL_CONNECTIVITY = 745;
+    // Private DNS is broken in strict mode
+    NOTE_NETWORK_PRIVATE_DNS_BROKEN = 746;
 
     // Notify the user that their work profile has been deleted
     // Package: android
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
deleted file mode 100644
index fbf6ca5..0000000
--- a/proto/src/wifi.proto
+++ /dev/null
@@ -1,2704 +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.
- */
-
-syntax = "proto2";
-
-package clearcut.connectivity;
-
-option java_package = "com.android.server.wifi";
-option java_outer_classname = "WifiMetricsProto";
-
-// The information about the Wifi events.
-message WifiLog {
-
-  // Session information that gets logged for every Wifi connection.
-  repeated ConnectionEvent connection_event = 1;
-
-  // Number of saved networks in the user profile.
-  optional int32 num_saved_networks = 2;
-
-  // Number of open networks in the saved networks.
-  optional int32 num_open_networks = 3;
-
-  // Number of legacy personal networks.
-  optional int32 num_legacy_personal_networks = 4;
-
-  // Number of legacy enterprise networks.
-  optional int32 num_legacy_enterprise_networks = 5;
-
-  // Does the user have location setting enabled.
-  optional bool is_location_enabled = 6;
-
-  // Does the user have scanning enabled.
-  optional bool is_scanning_always_enabled = 7;
-
-  // Number of times user toggled wifi using the settings menu.
-  optional int32 num_wifi_toggled_via_settings = 8;
-
-  // Number of times user toggled wifi using the airplane menu.
-  optional int32 num_wifi_toggled_via_airplane = 9;
-
-  // Number of networks added by the user.
-  optional int32 num_networks_added_by_user = 10;
-
-  // Number of networks added by applications.
-  optional int32 num_networks_added_by_apps = 11;
-
-  // Number scans that returned empty results.
-  optional int32 num_empty_scan_results = 12;
-
-  // Number scans that returned at least one result.
-  optional int32 num_non_empty_scan_results = 13;
-
-  // Number of single scans requests.
-  optional int32 num_oneshot_scans = 14;
-
-  // Number of repeated background scans that were scheduled to the chip.
-  optional int32 num_background_scans = 15;
-
-  // Error codes that a scan can result in.
-  enum ScanReturnCode {
-
-    // Return Code is unknown.
-    SCAN_UNKNOWN = 0;
-
-    // Scan was successful.
-    SCAN_SUCCESS = 1;
-
-    // Scan was successfully started, but was interrupted.
-    SCAN_FAILURE_INTERRUPTED = 2;
-
-    //  Scan failed to start because of invalid configuration
-    //  (bad channel, etc).
-    SCAN_FAILURE_INVALID_CONFIGURATION = 3;
-
-    // Could not start a scan because wifi is disabled.
-    FAILURE_WIFI_DISABLED = 4;
-
-  }
-
-  // Mapping of error codes to the number of times that scans resulted
-  // in that error.
-  repeated ScanReturnEntry scan_return_entries = 16;
-
-  message ScanReturnEntry {
-
-    // Return code of the scan.
-    optional ScanReturnCode scan_return_code = 1;
-
-    // Number of entries that were found in the scan.
-    optional int32 scan_results_count = 2;
-  }
-
-  // State of the Wifi.
-  enum WifiState {
-
-    // State is unknown.
-    WIFI_UNKNOWN = 0;
-
-    // Wifi is disabled.
-    WIFI_DISABLED = 1;
-
-    // Wifi is enabled.
-    WIFI_DISCONNECTED = 2;
-
-    // Wifi is enabled and associated with an AP.
-    WIFI_ASSOCIATED = 3;
-  }
-
-  // Mapping of system state to the number of times that scans were requested in
-  // that state
-  repeated WifiSystemStateEntry wifi_system_state_entries = 17;
-
-  message WifiSystemStateEntry {
-
-    // Current WiFi state.
-    optional WifiState wifi_state = 1;
-
-    // Count of scans in state.
-    optional int32 wifi_state_count = 2;
-
-    // Is screen on.
-    optional bool is_screen_on = 3;
-  }
-
-  // Mapping of Error/Success codes to the number of background scans that resulted in it
-  repeated ScanReturnEntry background_scan_return_entries = 18;
-
-  // Mapping of system state to the number of times that Background scans were requested in that
-  // state
-  repeated WifiSystemStateEntry background_scan_request_state = 19;
-
-  // Total number of times the Watchdog of Last Resort triggered, resetting the wifi stack
-  optional int32 num_last_resort_watchdog_triggers = 20;
-
-  // Total number of networks over bad association threshold when watchdog triggered
-  optional int32 num_last_resort_watchdog_bad_association_networks_total = 21;
-
-  // Total number of networks over bad authentication threshold when watchdog triggered
-  optional int32 num_last_resort_watchdog_bad_authentication_networks_total = 22;
-
-  // Total number of networks over bad dhcp threshold when watchdog triggered
-  optional int32 num_last_resort_watchdog_bad_dhcp_networks_total = 23;
-
-  // Total number of networks over bad other threshold when watchdog triggered
-  optional int32 num_last_resort_watchdog_bad_other_networks_total = 24;
-
-  // Total count of networks seen when watchdog triggered
-  optional int32 num_last_resort_watchdog_available_networks_total = 25;
-
-  // Total count of triggers with atleast one bad association network
-  optional int32 num_last_resort_watchdog_triggers_with_bad_association = 26;
-
-  // Total count of triggers with atleast one bad authentication network
-  optional int32 num_last_resort_watchdog_triggers_with_bad_authentication = 27;
-
-  // Total count of triggers with atleast one bad dhcp network
-  optional int32 num_last_resort_watchdog_triggers_with_bad_dhcp = 28;
-
-  // Total count of triggers with atleast one bad other network
-  optional int32 num_last_resort_watchdog_triggers_with_bad_other = 29;
-
-  // Count of times connectivity watchdog confirmed pno is working
-  optional int32 num_connectivity_watchdog_pno_good = 30;
-
-  // Count of times connectivity watchdog found pno not working
-  optional int32 num_connectivity_watchdog_pno_bad = 31;
-
-  // Count of times connectivity watchdog confirmed background scan is working
-  optional int32 num_connectivity_watchdog_background_good = 32;
-
-  // Count of times connectivity watchdog found background scan not working
-  optional int32 num_connectivity_watchdog_background_bad = 33;
-
-  // The time duration represented by this wifi log, from start to end of capture
-  optional int32 record_duration_sec = 34;
-
-  // Counts the occurrences of each individual RSSI poll level
-  repeated RssiPollCount rssi_poll_rssi_count = 35;
-
-  // Total number of times WiFi connected immediately after a Last Resort Watchdog trigger,
-  // without new networks becoming available.
-  optional int32 num_last_resort_watchdog_successes = 36;
-
-  // Total number of saved hidden networks
-  optional int32 num_hidden_networks = 37;
-
-  // Total number of saved passpoint / hotspot 2.0 networks
-  optional int32 num_passpoint_networks = 38;
-
-  // Total number of scan results
-  optional int32 num_total_scan_results = 39;
-
-  // Total number of scan results for open networks
-  optional int32 num_open_network_scan_results = 40;
-
-  // Total number of scan results for legacy personal networks
-  optional int32 num_legacy_personal_network_scan_results = 41;
-
-  // Total number of scan results for legacy enterprise networks
-  optional int32 num_legacy_enterprise_network_scan_results = 42;
-
-  // Total number of scan results for hidden networks
-  optional int32 num_hidden_network_scan_results = 43;
-
-  // Total number of scan results for hotspot 2.0 r1 networks
-  optional int32 num_hotspot2_r1_network_scan_results = 44;
-
-  // Total number of scan results for hotspot 2.0 r2 networks
-  optional int32 num_hotspot2_r2_network_scan_results = 45;
-
-  // Total number of scans handled by framework (oneshot or otherwise)
-  optional int32 num_scans = 46;
-
-  // Counts the occurrences of each alert reason.
-  repeated AlertReasonCount alert_reason_count = 47;
-
-  // Counts the occurrences of each Wifi score
-  repeated WifiScoreCount wifi_score_count = 48;
-
-  // Histogram of Soft AP Durations
-  repeated SoftApDurationBucket soft_ap_duration = 49;
-
-  // Histogram of Soft AP ReturnCode
-  repeated SoftApReturnCodeCount soft_ap_return_code = 50;
-
-  // Histogram of the delta between scan result RSSI and RSSI polls
-  repeated RssiPollCount rssi_poll_delta_count = 51;
-
-  // List of events
-  repeated StaEvent sta_event_list = 52;
-
-  // Total number of times WiFi HAL crashed.
-  optional int32 num_hal_crashes = 53;
-
-  // Total number of times WiFicond crashed.
-  optional int32 num_wificond_crashes = 54;
-
-  // Indicates the number of times an error was encountered in
-  // Wifi HAL on |WifiNative.setupInterfaceForClientMode|.
-  optional int32 num_setup_client_interface_failure_due_to_hal = 55;
-
-  // Indicates the number of times an error was encountered in
-  // Wificond on |WifiNative.setupInterfaceForClientMode|.
-  optional int32 num_setup_client_interface_failure_due_to_wificond = 56;
-
-  // Wi-Fi Aware metrics
-  optional WifiAwareLog wifi_aware_log = 57;
-
-  // Number of saved Passpoint providers in user profile.
-  optional int32 num_passpoint_providers = 58;
-
-  // Count of times Passpoint provider being installed.
-  optional int32 num_passpoint_provider_installation = 59;
-
-  // Count of times Passpoint provivider is installed successfully.
-  optional int32 num_passpoint_provider_install_success = 60;
-
-  // Count of times Passpoint provider is being uninstalled.
-  optional int32 num_passpoint_provider_uninstallation = 61;
-
-  // Count of times Passpoint provider is uninstalled successfully.
-  optional int32 num_passpoint_provider_uninstall_success = 62;
-
-  // Count of saved Passpoint providers device has ever connected to.
-  optional int32 num_passpoint_providers_successfully_connected = 63;
-
-  // Histogram counting instances of scans with N many ScanResults with unique ssids
-  repeated NumConnectableNetworksBucket total_ssids_in_scan_histogram = 64;
-
-  // Histogram counting instances of scans with N many ScanResults/bssids
-  repeated NumConnectableNetworksBucket total_bssids_in_scan_histogram = 65;
-
-  // Histogram counting instances of scans with N many unique open ssids
-  repeated NumConnectableNetworksBucket available_open_ssids_in_scan_histogram = 66;
-
-  // Histogram counting instances of scans with N many bssids for open networks
-  repeated NumConnectableNetworksBucket available_open_bssids_in_scan_histogram = 67;
-
-  // Histogram counting instances of scans with N many unique ssids for saved networks
-  repeated NumConnectableNetworksBucket available_saved_ssids_in_scan_histogram = 68;
-
-  // Histogram counting instances of scans with N many bssids for saved networks
-  repeated NumConnectableNetworksBucket available_saved_bssids_in_scan_histogram = 69;
-
-  // Histogram counting instances of scans with N many unique SSIDs for open or saved networks
-  repeated NumConnectableNetworksBucket available_open_or_saved_ssids_in_scan_histogram = 70;
-
-  // Histogram counting instances of scans with N many BSSIDs for open or saved networks
-  repeated NumConnectableNetworksBucket available_open_or_saved_bssids_in_scan_histogram = 71;
-
-  // Histogram counting instances of scans with N many ScanResults matching unique saved passpoint providers
-  repeated NumConnectableNetworksBucket available_saved_passpoint_provider_profiles_in_scan_histogram = 72;
-
-  // Histogram counting instances of scans with N many ScanResults BSSIDs matching a saved passpoint provider
-  repeated NumConnectableNetworksBucket available_saved_passpoint_provider_bssids_in_scan_histogram = 73;
-
-  // Counts the number of AllSingleScanLister.onResult calls with a full band scan result
-  optional int32 full_band_all_single_scan_listener_results = 74;
-
-  // Counts the number of AllSingleScanLister.onResult calls with a partial (channels) scan result
-  optional int32 partial_all_single_scan_listener_results = 75;
-
-  // Pno scan metrics
-  optional PnoScanMetrics pno_scan_metrics = 76;
-
-  // Histogram of "Connect to Network" notifications.
-  // The notification Action should be unset.
-  repeated ConnectToNetworkNotificationAndActionCount connect_to_network_notification_count = 77;
-
-  // Histogram of "Connect to Network" notification user actions.
-  repeated ConnectToNetworkNotificationAndActionCount connect_to_network_notification_action_count = 78;
-
-  // The number of SSIDs blacklisted from recommendation by the open network
-  // notification recommender
-  optional int32 open_network_recommender_blacklist_size = 79;
-
-  // Is the available network notification feature turned on
-  optional bool is_wifi_networks_available_notification_on = 80;
-
-  // Count of recommendation updates made by the open network notification
-  // recommender
-  optional int32 num_open_network_recommendation_updates = 81;
-
-  // Count of connection attempts that were initiated unsuccessfully
-  optional int32 num_open_network_connect_message_failed_to_send = 82;
-
-  // Histogram counting instances of scans with N many HotSpot 2.0 R1 APs
-  repeated NumConnectableNetworksBucket observed_hotspot_r1_aps_in_scan_histogram = 83;
-
-  // Histogram counting instances of scans with N many HotSpot 2.0 R2 APs
-  repeated NumConnectableNetworksBucket observed_hotspot_r2_aps_in_scan_histogram = 84;
-
-  // Histogram counting instances of scans with N many unique HotSpot 2.0 R1 ESS.
-  // Where ESS is defined as the (HESSID, ANQP Domain ID), (SSID, ANQP Domain ID) or
-  // (SSID, BSSID) tuple depending on AP configuration (in the above priority
-  // order).
-  repeated NumConnectableNetworksBucket observed_hotspot_r1_ess_in_scan_histogram = 85;
-
-  // Histogram counting instances of scans with N many unique HotSpot 2.0 R2 ESS.
-  // Where ESS is defined as the (HESSID, ANQP Domain ID), (SSID, ANQP Domain ID) or
-  // (SSID, BSSID) tuple depending on AP configuration (in the above priority
-  // order).
-  repeated NumConnectableNetworksBucket observed_hotspot_r2_ess_in_scan_histogram = 86;
-
-  // Histogram counting number of HotSpot 2.0 R1 APs per observed ESS in a scan
-  // (one value added per unique ESS - potentially multiple counts per single
-  // scan!)
-  repeated NumConnectableNetworksBucket observed_hotspot_r1_aps_per_ess_in_scan_histogram = 87;
-
-  // Histogram counting number of HotSpot 2.0 R2 APs per observed ESS in a scan
-  // (one value added per unique ESS - potentially multiple counts per single
-  // scan!)
-  repeated NumConnectableNetworksBucket observed_hotspot_r2_aps_per_ess_in_scan_histogram = 88;
-
-  // SoftAP event list tracking sessions and client counts in tethered mode
-  repeated SoftApConnectedClientsEvent soft_ap_connected_clients_events_tethered = 89;
-
-  // SoftAP event list tracking sessions and client counts in local only mode
-  repeated SoftApConnectedClientsEvent soft_ap_connected_clients_events_local_only = 90;
-
-  // Wps connection metrics
-  optional WpsMetrics wps_metrics = 91;
-
-  // Wifi power statistics
-  optional WifiPowerStats wifi_power_stats = 92;
-
-  // Number of connectivity single scan requests.
-  optional int32 num_connectivity_oneshot_scans = 93;
-
-  // WifiWake statistics
-  optional WifiWakeStats wifi_wake_stats = 94;
-
-  // Histogram counting instances of scans with N many 802.11mc (RTT) supporting APs
-  repeated NumConnectableNetworksBucket observed_80211mc_supporting_aps_in_scan_histogram = 95;
-
-  // Total number of times supplicant crashed.
-  optional int32 num_supplicant_crashes = 96;
-
-  // Total number of times hostapd crashed.
-  optional int32 num_hostapd_crashes = 97;
-
-  // Indicates the number of times an error was encountered in
-  // supplicant on |WifiNative.setupInterfaceForClientMode|.
-  optional int32 num_setup_client_interface_failure_due_to_supplicant = 98;
-
-  // Indicates the number of times an error was encountered in
-  // Wifi HAL on |WifiNative.setupInterfaceForSoftApMode|.
-  optional int32 num_setup_soft_ap_interface_failure_due_to_hal = 99;
-
-  // Indicates the number of times an error was encountered in
-  // Wifi HAL on |WifiNative.setupInterfaceForSoftApMode|.
-  optional int32 num_setup_soft_ap_interface_failure_due_to_wificond = 100;
-
-  // Indicates the number of times an error was encountered in
-  // Wifi HAL on |WifiNative.setupInterfaceForSoftApMode|.
-  optional int32 num_setup_soft_ap_interface_failure_due_to_hostapd = 101;
-
-  // Indicates the number of times we got an interface down in client mode.
-  optional int32 num_client_interface_down = 102;
-
-  // Indicates the number of times we got an interface down in softap mode.
-  optional int32 num_soft_ap_interface_down = 103;
-
-  // Indicates the number of scan requests from external apps.
-  optional int32 num_external_app_oneshot_scan_requests = 104;
-
-  // Indicates the number of times a scan request from an external foreground app was throttled.
-  optional int32 num_external_foreground_app_oneshot_scan_requests_throttled = 105;
-
-  // Indicates the number of times a scan request from an external background app was throttled.
-  optional int32 num_external_background_app_oneshot_scan_requests_throttled = 106;
-
-  // WifiLastResortWatchdog time milliseconds delta between trigger and first connection success
-  optional int64 watchdog_trigger_to_connection_success_duration_ms = 107 [default = -1];
-
-  // The number of times wifi experienced failures after watchdog has already been triggered and is
-  // waiting for a connection success
-  optional int64 watchdog_total_connection_failure_count_after_trigger = 108;
-
-  // Number of times DFS channel scans are requested in single scan requests.
-  optional int32 num_oneshot_has_dfs_channel_scans = 109;
-
-  // Wi-Fi RTT metrics
-  optional WifiRttLog wifi_rtt_log = 110;
-
-  // Flag which indicates if Connected MAC Randomization is enabled
-  optional bool is_mac_randomization_on = 111 [default = false];
-
-  // Number of radio mode changes to MCC (Multi channel concurrency).
-  optional int32 num_radio_mode_change_to_mcc = 112;
-
-  // Number of radio mode changes to SCC (Single channel concurrency).
-  optional int32 num_radio_mode_change_to_scc = 113;
-
-  // Number of radio mode changes to SBS (Single band simultaneous).
-  optional int32 num_radio_mode_change_to_sbs = 114;
-
-  // Number of radio mode changes to DBS (Dual band simultaneous).
-  optional int32 num_radio_mode_change_to_dbs = 115;
-
-  // Number of times the firmware picked a SoftAp channel not satisfying user band preference.
-  optional int32 num_soft_ap_user_band_preference_unsatisfied = 116;
-
-  // Identifier for experimental scoring parameter settings.
-  optional string score_experiment_id = 117;
-
-  // Data on wifi radio usage
-  optional WifiRadioUsage wifi_radio_usage = 118;
-
-  // Stores settings values used for metrics testing.
-  optional ExperimentValues experiment_values = 119;
-
-  // List of WifiIsUnusableEvents which get logged when we notice that WiFi is unusable.
-  // Collected only when WIFI_IS_UNUSABLE_EVENT_METRICS_ENABLED Settings is enabled.
-  repeated WifiIsUnusableEvent wifi_is_unusable_event_list = 120;
-
-  // Counts the occurrences of each link speed (Mbps) level
-  // with rssi (dBm) and rssi^2 sums (dBm^2)
-  repeated LinkSpeedCount link_speed_counts = 121;
-
-  // Number of times the SarManager failed to register SAR sensor listener
-  optional int32 num_sar_sensor_registration_failures = 122;
-
-  // Hardware revision (EVT, DVT, PVT etc.)
-  optional string hardware_revision = 124;
-
-  // Total wifi link layer usage data over the logging duration in ms.
-  optional WifiLinkLayerUsageStats wifi_link_layer_usage_stats = 125;
-
-  // Multiple lists of timestamped link layer stats with labels to represent whether wifi is usable
-  repeated WifiUsabilityStats wifi_usability_stats_list = 126;
-
-  // Counts the occurrences of each Wifi usability score provided by external app
-  repeated WifiUsabilityScoreCount wifi_usability_score_count = 127;
-
-  // List of PNO scan stats, one element for each mobility state
-  repeated DeviceMobilityStatePnoScanStats mobility_state_pno_stats_list = 128;
-
-  // Wifi p2p statistics
-  optional WifiP2pStats wifi_p2p_stats = 129;
-
-  // Easy Connect (DPP) metrics
-  optional WifiDppLog wifi_dpp_log = 130;
-
-  // Number of Enhanced Open (OWE) networks in the saved networks.
-  optional int32 num_enhanced_open_networks = 131;
-
-  // Number of WPA3-Personal networks.
-  optional int32 num_wpa3_personal_networks = 132;
-
-  // Number of WPA3-Enterprise networks.
-  optional int32 num_wpa3_enterprise_networks = 133;
-
-  // Total number of scan results for Enhanced open networks
-  optional int32 num_enhanced_open_network_scan_results = 134;
-
-  // Total number of scan results for WPA3-Personal networks
-  optional int32 num_wpa3_personal_network_scan_results = 135;
-
-  // Total number of scan results for WPA3-Enterprise networks
-  optional int32 num_wpa3_enterprise_network_scan_results = 136;
-
-  // WifiConfigStore read/write metrics.
-  optional WifiConfigStoreIO wifi_config_store_io = 137;
-
-  // Total number of saved networks with mac randomization enabled.
-  optional int32 num_saved_networks_with_mac_randomization = 138;
-
-  // Link Probe metrics
-  optional LinkProbeStats link_probe_stats = 139;
-
-  // List of NetworkSelectionExperimentDecisions stats for each experiment
-  repeated NetworkSelectionExperimentDecisions network_selection_experiment_decisions_list = 140;
-
-  // Network Request API surface metrics.
-  optional WifiNetworkRequestApiLog wifi_network_request_api_log = 141;
-
-  // Network Suggestion API surface metrics.
-  optional WifiNetworkSuggestionApiLog wifi_network_suggestion_api_log = 142;
-
-  // WifiLock statistics
-  optional WifiLockStats wifi_lock_stats = 143;
-
-  // Stats on number of times Wi-Fi is turned on/off though the WifiManager#setWifiEnabled API
-  optional WifiToggleStats wifi_toggle_stats = 144;
-
-  // Number of times WifiManager#addOrUpdateNetwork is called.
-  optional int32 num_add_or_update_network_calls = 145;
-
-  // Number of times WifiManager#enableNetwork is called.
-  optional int32 num_enable_network_calls = 146;
-
-  // Passpoint provison metrics
-  optional PasspointProvisionStats passpoint_provision_stats = 147;
-
-  // Histogram of the EAP method type of all installed Passpoint profiles for R1
-  repeated PasspointProfileTypeCount installed_passpoint_profile_type_for_r1 = 123;
-
-  // Histogram of the EAP method type of all installed Passpoint profiles for R2
-  repeated PasspointProfileTypeCount installed_passpoint_profile_type_for_r2 = 148;
-
-  // Histogram of Tx link speed at 2G
-  repeated Int32Count tx_link_speed_count_2g = 149;
-
-  // Histogram of Tx link speed at 5G low band
-  repeated Int32Count tx_link_speed_count_5g_low = 150;
-
-  // Histogram of Tx link speed at 5G middle band
-  repeated Int32Count tx_link_speed_count_5g_mid = 151;
-
-  // Histogram of Tx link speed at 5G high band
-  repeated Int32Count tx_link_speed_count_5g_high = 152;
-
-  // Histogram of Rx link speed at 2G
-  repeated Int32Count rx_link_speed_count_2g = 153;
-
-  // Histogram of Rx link speed at 5G low band
-  repeated Int32Count rx_link_speed_count_5g_low = 154;
-
-  // Histogram of Rx link speed at 5G middle band
-  repeated Int32Count rx_link_speed_count_5g_mid = 155;
-
-  // Histogram of Rx link speed at 5G high band
-  repeated Int32Count rx_link_speed_count_5g_high = 156;
-}
-
-// Information that gets logged for every WiFi connection.
-message RouterFingerPrint {
-
-  enum RoamType {
-
-    // Type is unknown.
-    ROAM_TYPE_UNKNOWN = 0;
-
-    // No roaming - usually happens on a single band (2.4 GHz) router.
-    ROAM_TYPE_NONE = 1;
-
-    // Enterprise router.
-    ROAM_TYPE_ENTERPRISE = 2;
-
-    // DBDC => Dual Band Dual Concurrent essentially a router that
-    // supports both 2.4 GHz and 5 GHz bands.
-    ROAM_TYPE_DBDC = 3;
-  }
-
-  enum Auth {
-
-    // Auth is unknown.
-    AUTH_UNKNOWN = 0;
-
-    // No authentication.
-    AUTH_OPEN = 1;
-
-    // If the router uses a personal authentication.
-    AUTH_PERSONAL = 2;
-
-    // If the router is setup for enterprise authentication.
-    AUTH_ENTERPRISE = 3;
-  }
-
-  enum RouterTechnology {
-
-    // Router is unknown.
-    ROUTER_TECH_UNKNOWN = 0;
-
-    // Router Channel A.
-    ROUTER_TECH_A = 1;
-
-    // Router Channel B.
-    ROUTER_TECH_B = 2;
-
-    // Router Channel G.
-    ROUTER_TECH_G = 3;
-
-    // Router Channel N.
-    ROUTER_TECH_N = 4;
-
-    // Router Channel AC.
-    ROUTER_TECH_AC = 5;
-
-    // When the channel is not one of the above.
-    ROUTER_TECH_OTHER = 6;
-  }
-
-  optional RoamType roam_type = 1;
-
-  // Channel on which the connection takes place.
-  optional int32 channel_info = 2;
-
-  // DTIM setting of the router.
-  optional int32 dtim = 3;
-
-  // Authentication scheme of the router.
-  optional Auth authentication = 4;
-
-  // If the router is hidden.
-  optional bool hidden = 5;
-
-  // Channel information.
-  optional RouterTechnology router_technology = 6;
-
-  // whether ipv6 is supported.
-  optional bool supports_ipv6 = 7;
-
-  // If the router is a passpoint / hotspot 2.0 network
-  optional bool passpoint = 8;
-}
-
-message ConnectionEvent {
-
-  // Roam Type.
-  enum RoamType {
-
-    // Type is unknown.
-    ROAM_UNKNOWN = 0;
-
-    // No roaming.
-    ROAM_NONE = 1;
-
-    // DBDC roaming.
-    ROAM_DBDC = 2;
-
-    // Enterprise roaming.
-    ROAM_ENTERPRISE = 3;
-
-    // User selected roaming.
-    ROAM_USER_SELECTED = 4;
-
-    // Unrelated.
-    ROAM_UNRELATED = 5;
-  }
-
-  // Connectivity Level Failure.
-  enum ConnectivityLevelFailure {
-
-    // Failure is unknown.
-    HLF_UNKNOWN = 0;
-
-    // No failure.
-    HLF_NONE = 1;
-
-    // DHCP failure.
-    HLF_DHCP = 2;
-
-    // No internet connection.
-    HLF_NO_INTERNET = 3;
-
-    // No internet connection.
-    HLF_UNWANTED = 4;
-  }
-
-  // Level 2 failure reason.
-  enum Level2FailureReason {
-
-    // Unknown default
-    FAILURE_REASON_UNKNOWN = 0;
-
-    // The reason code if there is no error during authentication. It could
-    // also imply that there no authentication in progress.
-    AUTH_FAILURE_NONE = 1;
-
-    // The reason code if there was a timeout authenticating.
-    AUTH_FAILURE_TIMEOUT = 2;
-
-    // The reason code if there was a wrong password while authenticating.
-    AUTH_FAILURE_WRONG_PSWD = 3;
-
-    // The reason code if there was EAP failure while authenticating.
-    AUTH_FAILURE_EAP_FAILURE = 4;
-  }
-
-  // Entity that recommended connecting to this network.
-  enum ConnectionNominator {
-    // Unknown nominator
-    NOMINATOR_UNKNOWN = 0;
-
-    // User selected network manually
-    NOMINATOR_MANUAL = 1;
-
-    // Saved network
-    NOMINATOR_SAVED = 2;
-
-    // Suggestion API
-    NOMINATOR_SUGGESTION = 3;
-
-    // Passpoint
-    NOMINATOR_PASSPOINT = 4;
-
-    // Carrier suggestion
-    NOMINATOR_CARRIER = 5;
-
-    // External scorer
-    NOMINATOR_EXTERNAL_SCORED = 6;
-
-    // Network Specifier
-    NOMINATOR_SPECIFIER = 7;
-
-    // User connected choice override
-    NOMINATOR_SAVED_USER_CONNECT_CHOICE = 8;
-
-    // Open Network Available Pop-up
-    NOMINATOR_OPEN_NETWORK_AVAILABLE = 9;
-  }
-
-  // Start time of the connection.
-  optional int64 start_time_millis = 1;// [(datapol.semantic_type) = ST_TIMESTAMP];
-
-  // Duration to connect.
-  optional int32 duration_taken_to_connect_millis = 2;
-
-  // Router information.
-  optional RouterFingerPrint router_fingerprint = 3;
-
-  // RSSI at the start of the connection.
-  optional int32 signal_strength = 4;
-
-  // Roam Type.
-  optional RoamType roam_type = 5;
-
-  // Result of the connection.
-  optional int32 connection_result = 6;
-
-  // Reasons for level 2 failure (needs to be coordinated with wpa-supplicant).
-  optional int32 level_2_failure_code = 7;
-
-  // Failures that happen at the connectivity layer.
-  optional ConnectivityLevelFailure connectivity_level_failure_code = 8;
-
-  // Has bug report been taken.
-  optional bool automatic_bug_report_taken = 9;
-
-  // Connection is using locally generated random MAC address.
-  optional bool use_randomized_mac = 10 [default = false];
-
-  // Who chose to connect.
-  optional ConnectionNominator connection_nominator = 11;
-
-  // The currently running network selector when this connection event occurred.
-  optional int32 network_selector_experiment_id = 12;
-
-  // Breakdown of level_2_failure_code with more detailed reason.
-  optional Level2FailureReason level_2_failure_reason = 13
-          [default = FAILURE_REASON_UNKNOWN];
-}
-
-// Number of occurrences of a specific RSSI poll rssi value
-message RssiPollCount {
-  // RSSI
-  optional int32 rssi = 1;
-
-  // Number of RSSI polls with 'rssi'
-  optional int32 count = 2;
-
-  // Beacon frequency of the channel in MHz
-  optional int32 frequency = 3;
-}
-
-// Number of occurrences of a specific alert reason value
-message AlertReasonCount {
-  // Alert reason
-  optional int32 reason = 1;
-
-  // Number of alerts with |reason|.
-  optional int32 count = 2;
-}
-
-// Counts the number of instances of a specific Wifi Score calculated by WifiScoreReport
-message WifiScoreCount {
-  // Wifi Score
-  optional int32 score = 1;
-
-  // Number of Wifi score reports with this score
-  optional int32 count = 2;
-}
-
-// Counts the number of instances of a specific Wifi Usability Score
-message WifiUsabilityScoreCount {
-  // Wifi Usability Score
-  optional int32 score = 1;
-
-  // Number of Wifi score reports with this score
-  optional int32 count = 2;
-}
-
-// Number of occurrences of a specific link speed (Mbps)
-// and sum of rssi (dBm) and rssi^2 (dBm^2)
-message LinkSpeedCount {
-  // Link speed (Mbps)
-  optional int32 link_speed_mbps = 1;
-
-  // Number of RSSI polls with link_speed
-  optional int32 count = 2;
-
-  // Sum of absolute values of rssi values (dBm)
-  optional int32 rssi_sum_dbm = 3;
-
-  // Sum of squares of rssi values (dBm^2)
-  optional int64 rssi_sum_of_squares_dbm_sq = 4;
-}
-
-
-// Number of occurrences of Soft AP session durations
-message SoftApDurationBucket {
-  // Bucket covers duration : [duration_sec, duration_sec + bucket_size_sec)
-  // The (inclusive) lower bound of Soft AP session duration represented by this bucket
-  optional int32 duration_sec = 1;
-
-  // The size of this bucket
-  optional int32 bucket_size_sec = 2;
-
-  // Number of soft AP session durations that fit into this bucket
-  optional int32 count = 3;
-}
-
-// Number of occurrences of a soft AP session return code
-message SoftApReturnCodeCount {
-
-  enum SoftApStartResult {
-
-    // SoftApManager return code unknown
-    SOFT_AP_RETURN_CODE_UNKNOWN = 0;
-
-    // SoftAp started successfully
-    SOFT_AP_STARTED_SUCCESSFULLY = 1;
-
-    // Catch all for failures with no specific failure reason
-    SOFT_AP_FAILED_GENERAL_ERROR = 2;
-
-    // SoftAp failed to start due to NO_CHANNEL error
-    SOFT_AP_FAILED_NO_CHANNEL = 3;
-  }
-
-  // Historical, no longer used for writing as of 01/2017.
-  optional int32 return_code = 1 [deprecated = true];
-
-  // Occurrences of this soft AP return code
-  optional int32 count = 2;
-
-  // Result of attempt to start SoftAp
-  optional SoftApStartResult start_result = 3;
-}
-
-message StaEvent {
-  message ConfigInfo {
-    // The set of key management protocols supported by this configuration.
-    optional uint32 allowed_key_management = 1 [default = 0];
-
-    // The set of security protocols supported by this configuration.
-    optional uint32 allowed_protocols = 2 [default = 0];
-
-    // The set of authentication protocols supported by this configuration.
-    optional uint32 allowed_auth_algorithms = 3 [default = 0];
-
-    // The set of pairwise ciphers for WPA supported by this configuration.
-    optional uint32 allowed_pairwise_ciphers = 4 [default = 0];
-
-    // The set of group ciphers supported by this configuration.
-    optional uint32 allowed_group_ciphers = 5;
-
-    // Is this a 'hidden network'
-    optional bool hidden_ssid = 6;
-
-    // Is this a Hotspot 2.0 / passpoint network
-    optional bool is_passpoint = 7;
-
-    // Is this an 'ephemeral' network (Not in saved network list, recommended externally)
-    optional bool is_ephemeral = 8;
-
-    // Has a successful connection ever been established using this WifiConfiguration
-    optional bool has_ever_connected = 9;
-
-    // RSSI of the scan result candidate associated with this WifiConfiguration
-    optional int32 scan_rssi = 10 [default = -127];
-
-    // Frequency of the scan result candidate associated with this WifiConfiguration
-    optional int32 scan_freq = 11 [default = -1];
-  }
-
-  enum EventType {
-    // Default/Invalid event
-    TYPE_UNKNOWN = 0;
-
-    // Supplicant Association Rejection event. Code contains the 802.11
-    TYPE_ASSOCIATION_REJECTION_EVENT = 1;
-
-    // Supplicant L2 event,
-    TYPE_AUTHENTICATION_FAILURE_EVENT = 2;
-
-    // Supplicant L2 event
-    TYPE_NETWORK_CONNECTION_EVENT = 3;
-
-    // Supplicant L2 event
-    TYPE_NETWORK_DISCONNECTION_EVENT = 4;
-
-    // Supplicant L2 event
-    TYPE_SUPPLICANT_STATE_CHANGE_EVENT = 5;
-
-    // Supplicant L2 event
-    TYPE_CMD_ASSOCIATED_BSSID = 6;
-
-    // IP Manager successfully completed IP Provisioning
-    TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL = 7;
-
-    // IP Manager failed to complete IP Provisioning
-    TYPE_CMD_IP_CONFIGURATION_LOST = 8;
-
-    // IP Manager lost reachability to network neighbors
-    TYPE_CMD_IP_REACHABILITY_LOST = 9;
-
-    // Indicator that Supplicant is targeting a BSSID for roam/connection
-    TYPE_CMD_TARGET_BSSID = 10;
-
-    // Wifi framework is initiating a connection attempt
-    TYPE_CMD_START_CONNECT = 11;
-
-    // Wifi framework is initiating a roaming connection attempt
-    TYPE_CMD_START_ROAM = 12;
-
-    // SystemAPI connect() command, Settings App
-    TYPE_CONNECT_NETWORK = 13;
-
-    // Network Agent has validated the internet connection (Captive Portal Check success, or user
-    // validation)
-    TYPE_NETWORK_AGENT_VALID_NETWORK = 14;
-
-    // Framework initiated disconnect. Sometimes generated to give an extra reason for a disconnect
-    // Should typically be followed by a NETWORK_DISCONNECTION_EVENT with a local_gen = true
-    TYPE_FRAMEWORK_DISCONNECT = 15;
-
-    // The NetworkAgent score for wifi has changed in a way that may impact
-    // connectivity
-    TYPE_SCORE_BREACH = 16;
-
-    // Framework changed Sta interface MAC address
-    TYPE_MAC_CHANGE = 17;
-
-    // Wifi is turned on
-    TYPE_WIFI_ENABLED = 18;
-
-    // Wifi is turned off
-    TYPE_WIFI_DISABLED = 19;
-
-    // The NetworkAgent Wifi usability score has changed in a way that may
-    // impact connectivity
-    TYPE_WIFI_USABILITY_SCORE_BREACH = 20;
-
-    // Link probe was performed
-    TYPE_LINK_PROBE = 21;
-  }
-
-  enum FrameworkDisconnectReason {
-    // default/none/unknown value
-    DISCONNECT_UNKNOWN = 0;
-
-    // API DISCONNECT
-    DISCONNECT_API = 1;
-
-    // Some framework internal reason (generic)
-    DISCONNECT_GENERIC = 2;
-
-    // Network Agent network validation failed, user signaled network unwanted
-    DISCONNECT_UNWANTED = 3;
-
-    // Roaming timed out
-    DISCONNECT_ROAM_WATCHDOG_TIMER = 4;
-
-    // P2P service requested wifi disconnect
-    DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST = 5;
-
-    // SIM was removed while using a SIM config
-    DISCONNECT_RESET_SIM_NETWORKS = 6;
-  }
-
-  // Authentication Failure reasons as reported through the API.
-  enum AuthFailureReason {
-    // Unknown default
-    AUTH_FAILURE_UNKNOWN = 0;
-
-    // The reason code if there is no error during authentication. It could also imply that there no
-    // authentication in progress,
-    AUTH_FAILURE_NONE = 1;
-
-    // The reason code if there was a timeout authenticating.
-    AUTH_FAILURE_TIMEOUT = 2;
-
-    // The reason code if there was a wrong password while authenticating.
-    AUTH_FAILURE_WRONG_PSWD = 3;
-
-    // The reason code if there was EAP failure while authenticating.
-    AUTH_FAILURE_EAP_FAILURE = 4;
-  }
-
-  // What event was this
-  optional EventType type = 1;
-
-  // 80211 death reason code, relevant to NETWORK_DISCONNECTION_EVENTs
-  optional int32 reason = 2 [default = -1];
-
-  // 80211 Association Status code, relevant to ASSOCIATION_REJECTION_EVENTs
-  optional int32 status = 3 [default = -1];
-
-  // Designates whether a NETWORK_DISCONNECT_EVENT was by the STA or AP
-  optional bool local_gen = 4 [default = false];
-
-  // Network information from the WifiConfiguration of a framework initiated connection attempt
-  optional ConfigInfo config_info = 5;
-
-  // RSSI from the last rssi poll (Only valid for active connections)
-  optional int32 last_rssi = 6 [default = -127];
-
-  // Link speed from the last rssi poll (Only valid for active connections)
-  optional int32 last_link_speed = 7 [default = -1];
-
-  // Frequency from the last rssi poll (Only valid for active connections)
-  optional int32 last_freq = 8 [default = -1];
-
-  // Enum used to define bit positions in the supplicant_state_change_bitmask
-  // See {@code frameworks/base/wifi/java/android/net/wifi/SupplicantState.java} for documentation
-  enum SupplicantState {
-    STATE_DISCONNECTED = 0;
-
-    STATE_INTERFACE_DISABLED = 1;
-
-    STATE_INACTIVE = 2;
-
-    STATE_SCANNING = 3;
-
-    STATE_AUTHENTICATING = 4;
-
-    STATE_ASSOCIATING = 5;
-
-    STATE_ASSOCIATED = 6;
-
-    STATE_FOUR_WAY_HANDSHAKE = 7;
-
-    STATE_GROUP_HANDSHAKE = 8;
-
-    STATE_COMPLETED = 9;
-
-    STATE_DORMANT = 10;
-
-    STATE_UNINITIALIZED = 11;
-
-    STATE_INVALID = 12;
-  }
-
-  // Bit mask of all supplicant state changes that occurred since the last event
-  optional uint32 supplicant_state_changes_bitmask = 9 [default = 0];
-
-  // The number of milliseconds that have elapsed since the device booted
-  optional int64 start_time_millis = 10 [default = 0];
-
-  optional FrameworkDisconnectReason framework_disconnect_reason = 11 [default = DISCONNECT_UNKNOWN];
-
-  // Flag which indicates if an association rejection event occurred due to a timeout
-  optional bool association_timed_out = 12 [default = false];
-
-  // Authentication failure reason, as reported by WifiManager (calculated from state & deauth code)
-  optional AuthFailureReason auth_failure_reason = 13 [default = AUTH_FAILURE_UNKNOWN];
-
-  // NetworkAgent score of connected wifi
-  optional int32 last_score = 14 [default = -1];
-
-  // NetworkAgent Wifi usability score of connected wifi
-  optional int32 last_wifi_usability_score = 15 [default = -1];
-
-  // Prediction horizon (in second) of Wifi usability score provided by external
-  // system app
-  optional int32 last_prediction_horizon_sec = 16 [default = -1];
-
-  // Only valid if event type == TYPE_LINK_PROBE.
-  // true if link probe succeeded, false otherwise.
-  optional bool link_probe_was_success = 17;
-
-  // Only valid if event type == TYPE_LINK_PROBE and link_probe_was_success == true.
-  // Elapsed time, in milliseconds, of a successful link probe.
-  optional int32 link_probe_success_elapsed_time_ms = 18;
-
-  // Only valid if event type == TYPE_LINK_PROBE and link_probe_was_success == false.
-  // Failure reason for an unsuccessful link probe.
-  optional LinkProbeStats.LinkProbeFailureReason link_probe_failure_reason = 19;
-}
-
-// Wi-Fi Aware metrics
-message WifiAwareLog {
-  // total number of unique apps that used Aware (measured on attach)
-  optional int32 num_apps = 1;
-
-  // total number of unique apps that used an identity callback when attaching
-  optional int32 num_apps_using_identity_callback = 2;
-
-  // maximum number of attaches for an app
-  optional int32 max_concurrent_attach_sessions_in_app = 3;
-
-  // histogram of attach request results
-  repeated NanStatusHistogramBucket histogram_attach_session_status = 4;
-
-  // maximum number of concurrent publish sessions in a single app
-  optional int32 max_concurrent_publish_in_app = 5;
-
-  // maximum number of concurrent subscribe sessions in a single app
-  optional int32 max_concurrent_subscribe_in_app = 6;
-
-  // maximum number of concurrent discovery (publish+subscribe) sessions in a single app
-  optional int32 max_concurrent_discovery_sessions_in_app = 7;
-
-  // maximum number of concurrent publish sessions in the system
-  optional int32 max_concurrent_publish_in_system = 8;
-
-  // maximum number of concurrent subscribe sessions in the system
-  optional int32 max_concurrent_subscribe_in_system = 9;
-
-  // maximum number of concurrent discovery (publish+subscribe) sessions in the system
-  optional int32 max_concurrent_discovery_sessions_in_system = 10;
-
-  // histogram of publish request results
-  repeated NanStatusHistogramBucket histogram_publish_status = 11;
-
-  // histogram of subscribe request results
-  repeated NanStatusHistogramBucket histogram_subscribe_status = 12;
-
-  // number of unique apps which experienced a discovery session creation failure due to lack of
-  // resources
-  optional int32 num_apps_with_discovery_session_failure_out_of_resources = 13;
-
-  // histogram of create ndp request results
-  repeated NanStatusHistogramBucket histogram_request_ndp_status = 14;
-
-  // histogram of create ndp out-of-band (OOB) request results
-  repeated NanStatusHistogramBucket histogram_request_ndp_oob_status = 15;
-
-  // maximum number of concurrent active data-interfaces (NDI) in a single app
-  optional int32 max_concurrent_ndi_in_app = 19;
-
-  // maximum number of concurrent active data-interfaces (NDI) in the system
-  optional int32 max_concurrent_ndi_in_system = 20;
-
-  // maximum number of concurrent data-paths (NDP) in a single app
-  optional int32 max_concurrent_ndp_in_app = 21;
-
-  // maximum number of concurrent data-paths (NDP) in the system
-  optional int32 max_concurrent_ndp_in_system = 22;
-
-  // maximum number of concurrent secure data-paths (NDP) in a single app
-  optional int32 max_concurrent_secure_ndp_in_app = 23;
-
-  // maximum number of concurrent secure data-paths (NDP) in the system
-  optional int32 max_concurrent_secure_ndp_in_system = 24;
-
-  // maximum number of concurrent data-paths (NDP) per data-interface (NDI)
-  optional int32 max_concurrent_ndp_per_ndi = 25;
-
-  // histogram of durations of Aware being available
-  repeated HistogramBucket histogram_aware_available_duration_ms = 26;
-
-  // histogram of durations of Aware being enabled
-  repeated HistogramBucket histogram_aware_enabled_duration_ms = 27;
-
-  // histogram of duration (in ms) of attach sessions
-  repeated HistogramBucket histogram_attach_duration_ms = 28;
-
-  // histogram of duration (in ms) of publish sessions
-  repeated HistogramBucket histogram_publish_session_duration_ms = 29;
-
-  // histogram of duration (in ms) of subscribe sessions
-  repeated HistogramBucket histogram_subscribe_session_duration_ms = 30;
-
-  // histogram of duration (in ms) of data-paths (NDP)
-  repeated HistogramBucket histogram_ndp_session_duration_ms = 31;
-
-  // histogram of usage (in MB) of data-paths (NDP)
-  repeated HistogramBucket histogram_ndp_session_data_usage_mb = 32;
-
-  // histogram of usage (in MB) of data-path creation time (in ms) measured as request -> confirm
-  repeated HistogramBucket histogram_ndp_creation_time_ms = 33;
-
-  // statistics for data-path (NDP) creation time (in ms) measured as request -> confirm: minimum
-  optional int64 ndp_creation_time_ms_min = 34;
-
-  // statistics for data-path (NDP) creation time (in ms) measured as request -> confirm: maximum
-  optional int64 ndp_creation_time_ms_max = 35;
-
-  // statistics for data-path (NDP) creation time (in ms) measured as request -> confirm: sum
-  optional int64 ndp_creation_time_ms_sum = 36;
-
-  // statistics for data-path (NDP) creation time (in ms) measured as request -> confirm: sum of sq
-  optional int64 ndp_creation_time_ms_sum_of_sq = 37;
-
-  // statistics for data-path (NDP) creation time (in ms) measured as request -> confirm: number of
-  // samples
-  optional int64 ndp_creation_time_ms_num_samples = 38;
-
-  // total time within the logging window that aware was available
-  optional int64 available_time_ms = 39;
-
-  // total time within the logging window that aware was enabled
-  optional int64 enabled_time_ms = 40;
-
-  // maximum number of concurrent publish sessions enabling ranging in a single app
-  optional int32 max_concurrent_publish_with_ranging_in_app = 41;
-
-  // maximum number of concurrent subscribe sessions specifying a geofence in a single app
-  optional int32 max_concurrent_subscribe_with_ranging_in_app = 42;
-
-  // maximum number of concurrent publish sessions enabling ranging in the system
-  optional int32 max_concurrent_publish_with_ranging_in_system = 43;
-
-  // maximum number of concurrent subscribe sessions specifying a geofence in the system
-  optional int32 max_concurrent_subscribe_with_ranging_in_system = 44;
-
-  // histogram of subscribe session geofence minimum (only when specified)
-  repeated HistogramBucket histogram_subscribe_geofence_min = 45;
-
-  // histogram of subscribe session geofence maximum (only when specified)
-  repeated HistogramBucket histogram_subscribe_geofence_max = 46;
-
-  // total number of subscribe sessions which enabled ranging
-  optional int32 num_subscribes_with_ranging = 47;
-
-  // total number of matches (service discovery indication) with ranging provided
-  optional int32 num_matches_with_ranging = 48;
-
-  // total number of matches (service discovery indication) for service discovery with ranging
-  // enabled which did not trigger ranging
-  optional int32 num_matches_without_ranging_for_ranging_enabled_subscribes = 49;
-
-  // Histogram bucket for Wi-Fi Aware logs. Range is [start, end)
-  message HistogramBucket {
-    // lower range of the bucket (inclusive)
-    optional int64 start = 1;
-
-    // upper range of the bucket (exclusive)
-    optional int64 end = 2;
-
-    // number of samples in the bucket
-    optional int32 count = 3;
-  }
-
-  // Status of various NAN operations
-  enum NanStatusTypeEnum {
-    // constant to be used by proto
-    UNKNOWN = 0;
-
-    // NAN operation succeeded
-    SUCCESS = 1;
-
-    // NAN Discovery Engine/Host driver failures
-    INTERNAL_FAILURE = 2;
-
-    // NAN OTA failures
-    PROTOCOL_FAILURE = 3;
-
-    // The publish/subscribe discovery session id is invalid
-    INVALID_SESSION_ID = 4;
-
-    // Out of resources to fufill request
-    NO_RESOURCES_AVAILABLE = 5;
-
-    // Invalid arguments passed
-    INVALID_ARGS = 6;
-
-    // Invalid peer id
-    INVALID_PEER_ID = 7;
-
-    // Invalid NAN data-path (ndp) id
-    INVALID_NDP_ID = 8;
-
-    // Attempting to enable NAN when not available, e.g. wifi is disabled
-    NAN_NOT_ALLOWED = 9;
-
-    // Over the air ACK not received
-    NO_OTA_ACK = 10;
-
-    // Attempting to enable NAN when already enabled
-    ALREADY_ENABLED = 11;
-
-    // Can't queue tx followup message foor transmission
-    FOLLOWUP_TX_QUEUE_FULL = 12;
-
-    // Unsupported concurrency of NAN and another feature - NAN disabled
-    UNSUPPORTED_CONCURRENCY_NAN_DISABLED = 13;
-
-    // Unknown NanStatusType
-    UNKNOWN_HAL_STATUS = 14;
-  }
-
-  // Histogram bucket for Wi-Fi Aware (NAN) status.
-  message NanStatusHistogramBucket {
-    // status type defining the bucket
-    optional NanStatusTypeEnum nan_status_type = 1;
-
-    // number of samples in the bucket
-    optional int32 count = 2;
-  }
-}
-
-// Data point used to build 'Number of Connectable Network' histograms
-message NumConnectableNetworksBucket {
-  // Number of connectable networks seen in a scan result
-  optional int32 num_connectable_networks = 1 [default = 0];
-
-  // Number of scan results with num_connectable_networks
-  optional int32 count = 2 [default = 0];
-}
-
-// Pno scan metrics
-// Here "Pno Scan" refers to the session of offloaded scans, these metrics count the result of a
-// single session, and not the individual scans within that session.
-message PnoScanMetrics {
-  // Total number of attempts to offload pno scans
-  optional int32 num_pno_scan_attempts = 1;
-
-  // Total number of pno scans failed
-  optional int32 num_pno_scan_failed = 2;
-
-  // Number of pno scans started successfully over offload
-  optional int32 num_pno_scan_started_over_offload = 3;
-
-  // Number of pno scans failed over offload
-  optional int32 num_pno_scan_failed_over_offload = 4;
-
-  // Total number of pno scans that found any network
-  optional int32 num_pno_found_network_events = 5;
-}
-
-// Number of occurrences for a particular "Connect to Network" Notification or
-// notification Action.
-message ConnectToNetworkNotificationAndActionCount {
-
-  // "Connect to Network" notifications
-  enum Notification {
-
-    // Default
-    NOTIFICATION_UNKNOWN = 0;
-
-    // Initial notification with a recommended network.
-    NOTIFICATION_RECOMMEND_NETWORK = 1;
-
-    // Notification when connecting to the recommended network.
-    NOTIFICATION_CONNECTING_TO_NETWORK = 2;
-
-    // Notification when successfully connected to the network.
-    NOTIFICATION_CONNECTED_TO_NETWORK = 3;
-
-    // Notification when failed to connect to network.
-    NOTIFICATION_FAILED_TO_CONNECT = 4;
-  }
-
-  // "Connect to Network" notification actions
-  enum Action {
-
-    // Default
-    ACTION_UNKNOWN = 0;
-
-    // User dismissed the "Connect to Network" notification.
-    ACTION_USER_DISMISSED_NOTIFICATION = 1;
-
-    // User tapped action button to connect to recommended network.
-    ACTION_CONNECT_TO_NETWORK = 2;
-
-    // User tapped action button to open Wi-Fi Settings.
-    ACTION_PICK_WIFI_NETWORK = 3;
-
-    // User tapped "Failed to connect" notification to open Wi-Fi Settings.
-    ACTION_PICK_WIFI_NETWORK_AFTER_CONNECT_FAILURE = 4;
-  }
-
-  // Recommenders of the "Connect to Network" notification
-  enum Recommender {
-
-    // Default.
-    RECOMMENDER_UNKNOWN = 0;
-
-    // Open Network Available recommender.
-    RECOMMENDER_OPEN = 1;
-  }
-
-  // Notification Type.
-  optional Notification notification = 1;
-
-  // Action Type.
-  optional Action action = 2;
-
-  // Recommender Type.
-  optional Recommender recommender = 3;
-
-  // Occurrences of this action.
-  optional int32 count = 4;
-}
-
-// SoftAP event tracking sessions and client counts
-message SoftApConnectedClientsEvent {
-
-  // Soft AP event Types
-  enum SoftApEventType {
-
-    // Soft AP is Up and ready for use
-    SOFT_AP_UP = 0;
-
-    // Soft AP is Down
-    SOFT_AP_DOWN = 1;
-
-    // Number of connected soft AP clients has changed
-    NUM_CLIENTS_CHANGED = 2;
-  }
-
-  // Soft AP channel bandwidth types
-  enum ChannelBandwidth {
-
-    BANDWIDTH_INVALID = 0;
-
-    BANDWIDTH_20_NOHT = 1;
-
-    BANDWIDTH_20 = 2;
-
-    BANDWIDTH_40 = 3;
-
-    BANDWIDTH_80 = 4;
-
-    BANDWIDTH_80P80 = 5;
-
-    BANDWIDTH_160 = 6;
-  }
-
-  // Type of event being recorded
-  optional SoftApEventType event_type = 1;
-
-  // Time passed since last boot in milliseconds
-  optional int64 time_stamp_millis = 2;
-
-  // Number of connected clients if event_type is NUM_CLIENTS_CHANGED, otherwise zero.
-  optional int32 num_connected_clients = 3;
-
-  // Channel frequency used for Soft AP
-  optional int32 channel_frequency = 4;
-
-  // Channel bandwidth used for Soft AP
-  optional ChannelBandwidth channel_bandwidth = 5;
-}
-
-// Wps connection metrics
-// Keeps track of Wi-Fi Protected Setup usage
-message WpsMetrics {
-  // Total number of wps connection attempts
-  optional int32 num_wps_attempts = 1;
-
-  // Total number of wps connection successes
-  optional int32 num_wps_success = 2;
-
-  // Total number of wps failures on start
-  optional int32 num_wps_start_failure = 3;
-
-  // Total number of wps overlap failure
-  optional int32 num_wps_overlap_failure = 4;
-
-  // Total number of wps timeout failure
-  optional int32 num_wps_timeout_failure = 5;
-
-  // Total number of other wps failure during connection
-  optional int32 num_wps_other_connection_failure = 6;
-
-  // Total number of supplicant failure after wps
-  optional int32 num_wps_supplicant_failure = 7;
-
-  // Total number of wps cancellation
-  optional int32 num_wps_cancellation = 8;
-}
-
-// Power stats for Wifi
-message WifiPowerStats {
-
-  // Duration of log (ms)
-  optional int64 logging_duration_ms = 1;
-
-  // Energy consumed by wifi (mAh)
-  optional double energy_consumed_mah = 2;
-
-  // Amount of time wifi is in idle (ms)
-  optional int64 idle_time_ms = 3;
-
-  // Amount of time wifi is in rx (ms)
-  optional int64 rx_time_ms = 4;
-
-  // Amount of time wifi is in tx (ms)
-  optional int64 tx_time_ms = 5;
-
-  // Amount of time kernel is active because of wifi data (ms)
-  optional int64 wifi_kernel_active_time_ms = 6;
-
-  // Number of packets sent (tx)
-  optional int64 num_packets_tx = 7;
-
-  // Number of bytes sent (tx)
-  optional int64 num_bytes_tx = 8;
-
-  // Number of packets received (rx)
-  optional int64 num_packets_rx = 9;
-
-  // Number of bytes sent (rx)
-  optional int64 num_bytes_rx = 10;
-
-  // Amount of time wifi is in sleep (ms)
-  optional int64 sleep_time_ms = 11;
-
-  // Amount of time wifi is scanning (ms)
-  optional int64 scan_time_ms = 12;
-
-  // Actual monitored rail energy consumed by wifi (mAh)
-  optional double monitored_rail_energy_consumed_mah = 13;
-}
-
-// Metrics for Wifi Wake
-message WifiWakeStats {
-  // An individual session for Wifi Wake
-  message Session {
-    // A Wifi Wake lifecycle event
-    message Event {
-      // Elapsed time in milliseconds since start of session.
-      optional int64 elapsed_time_millis = 1;
-
-      // Number of scans that have occurred since start of session.
-      optional int32 elapsed_scans = 2;
-    }
-
-    // Start time of session in milliseconds.
-    optional int64 start_time_millis = 1;
-
-    // The number of networks the lock was provided with at start.
-    optional int32 locked_networks_at_start = 2;
-
-    // The number of networks in the lock at the time of the initialize event. Only valid if
-    // initialize_event is recorded.
-    optional int32 locked_networks_at_initialize = 6;
-
-    // Event for fully initializing the WakeupLock (i.e. WakeupLock is "locked").
-    optional Event initialize_event = 7;
-
-    // Event for unlocking the WakeupLock. Does not occur if lock was initialized with 0 networks.
-    optional Event unlock_event = 3;
-
-    // Event for triggering wakeup.
-    optional Event wakeup_event = 4;
-
-    // Event for WifiWake reset event. This event marks the end of a session.
-    optional Event reset_event = 5;
-  }
-
-  // Total number of sessions for Wifi Wake.
-  optional int32 num_sessions = 1;
-
-  // Session information for every Wifi Wake session (up to a maximum of 10).
-  repeated Session sessions = 2;
-
-  // Number of ignored calls to start (due to WakeupController already being active).
-  optional int32 num_ignored_starts = 3;
-
-  // Number of Wifi Wake sessions that have recorded wakeup events.
-  optional int32 num_wakeups = 4;
-}
-
-// Metrics for Wi-Fi RTT
-message WifiRttLog {
-  // Number of RTT request API calls
-  optional int32 num_requests = 1;
-
-  // Histogram of RTT operation overall status
-  repeated RttOverallStatusHistogramBucket histogram_overall_status = 2;
-
-  // RTT to Access Points metrics
-  optional RttToPeerLog rtt_to_ap = 3;
-
-  // RTT to Wi-Fi Aware peers metrics
-  optional RttToPeerLog rtt_to_aware = 4;
-
-  // Metrics for a RTT to Peer (peer = AP or Wi-Fi Aware)
-  message RttToPeerLog {
-    // Total number of API calls
-    optional int32 num_requests = 1;
-
-    // Total number of individual requests
-    optional int32 num_individual_requests = 2;
-
-    // Total number of apps which requested RTT
-    optional int32 num_apps = 3;
-
-    // Histogram of total number of RTT requests by an app (WifiRttManager#startRanging)
-    repeated HistogramBucket histogram_num_requests_per_app = 4;
-
-    // Histogram of number of peers in a single RTT request (RangingRequest entries)
-    repeated HistogramBucket histogram_num_peers_per_request = 5;
-
-    // Histogram of status of individual RTT operations (RangingResult entries)
-    repeated RttIndividualStatusHistogramBucket histogram_individual_status = 6;
-
-    // Histogram of measured distances (RangingResult entries)
-    repeated HistogramBucket histogram_distance = 7;
-
-    // Histogram of interval of RTT requests by an app (WifiRttManager#startRanging)
-    repeated HistogramBucket histogram_request_interval_ms = 8;
-  }
-
-  // Histogram bucket for Wi-Fi RTT logs. Range is [start, end)
-  message HistogramBucket {
-    // lower range of the bucket (inclusive)
-    optional int64 start = 1;
-
-    // upper range of the bucket (exclusive)
-    optional int64 end = 2;
-
-    // number of samples in the bucket
-    optional int32 count = 3;
-  }
-
-  // Status codes for overall RTT operation
-  enum RttOverallStatusTypeEnum {
-    // constant to be used by proto
-    OVERALL_UNKNOWN = 0;
-
-    // RTT operation succeeded (individual results may still fail)
-    OVERALL_SUCCESS = 1;
-
-    // RTT operation failed (unspecified reason)
-    OVERALL_FAIL = 2;
-
-    // RTT operation failed since RTT was not available (e.g. Airplane mode)
-    OVERALL_RTT_NOT_AVAILABLE = 3;
-
-    // RTT operation timed-out: didn't receive response from HAL in expected time
-    OVERALL_TIMEOUT = 4;
-
-    // RTT operation aborted since the app is spamming the service
-    OVERALL_THROTTLE = 5;
-
-    // RTT request to HAL received immediate failure
-    OVERALL_HAL_FAILURE = 6;
-
-    // RTT to Wi-Fi Aware peer using PeerHandle failed to get a MAC address translation
-    OVERALL_AWARE_TRANSLATION_FAILURE = 7;
-
-    // RTT operation failed due to missing Location permission (post execution)
-    OVERALL_LOCATION_PERMISSION_MISSING = 8;
-  }
-
-  // Status codes for individual RTT operation
-  enum RttIndividualStatusTypeEnum {
-    // constant to be used by proto
-    UNKNOWN = 0;
-
-    // RTT operation succeeded
-    SUCCESS = 1;
-
-    // RTT failure: generic reason (no further information)
-    FAILURE = 2;
-
-    // Target STA does not respond to request
-    FAIL_NO_RSP = 3;
-
-    // Request rejected. Applies to 2-sided RTT only
-    FAIL_REJECTED = 4;
-
-    // Operation not scheduled
-    FAIL_NOT_SCHEDULED_YET = 5;
-
-    // Timing measurement times out
-    FAIL_TM_TIMEOUT = 6;
-
-    // Target on different channel, cannot range
-    FAIL_AP_ON_DIFF_CHANNEL = 7;
-
-    // Ranging not supported
-    FAIL_NO_CAPABILITY = 8;
-
-    // Request aborted for unknown reason
-    ABORTED = 9;
-
-    // Invalid T1-T4 timestamp
-    FAIL_INVALID_TS = 10;
-
-    // 11mc protocol failed
-    FAIL_PROTOCOL = 11;
-
-    // Request could not be scheduled
-    FAIL_SCHEDULE = 12;
-
-    // Responder cannot collaborate at time of request
-    FAIL_BUSY_TRY_LATER = 13;
-
-    // Bad request args
-    INVALID_REQ = 14;
-
-    // WiFi not enabled
-    NO_WIFI = 15;
-
-    // Responder overrides param info, cannot range with new params
-    FAIL_FTM_PARAM_OVERRIDE = 16;
-
-    // HAL did not provide a result to a framework request
-    MISSING_RESULT = 17;
-  }
-
-  // Histogram bucket for Wi-Fi RTT overall operation status
-  message RttOverallStatusHistogramBucket {
-    // status type defining the bucket
-    optional RttOverallStatusTypeEnum status_type = 1;
-
-    // number of samples in the bucket
-    optional int32 count = 2;
-  }
-
-  // Histogram bucket for Wi-Fi RTT individual operation status
-  message RttIndividualStatusHistogramBucket {
-    // status type defining the bucket
-    optional RttIndividualStatusTypeEnum status_type = 1;
-
-    // number of samples in the bucket
-    optional int32 count = 2;
-  }
-}
-
-// Usage data for the wifi radio while device is running on battery.
-message WifiRadioUsage {
-  // Duration of log (ms)
-  optional int64 logging_duration_ms = 1;
-
-  // Total time for which the radio is awake due to scan.
-  optional int64 scan_time_ms = 2;
-}
-
-message ExperimentValues {
-  // Indicates if we are logging WifiIsUnusableEvent in metrics
-  optional bool wifi_is_unusable_logging_enabled = 1;
-
-  // Minimum number of txBad to trigger a data stall
-  optional int32 wifi_data_stall_min_tx_bad = 2;
-
-  // Minimum number of txSuccess to trigger a data stall
-  // when rxSuccess is 0
-  optional int32 wifi_data_stall_min_tx_success_without_rx = 3;
-
-  // Indicates if we are logging LinkSpeedCount in metrics
-  optional bool link_speed_counts_logging_enabled = 4;
-
-  // Duration for evaluating Wifi condition to trigger a data stall
-  // measured in milliseconds
-  optional int32 data_stall_duration_ms = 5;
-
-  // Threshold of Tx throughput below which to trigger a data stall
-  // measured in Kbps
-  optional int32 data_stall_tx_tput_thr_kbps = 6;
-
-  // Threshold of Rx throughput below which to trigger a data stall
-  // measured in Kbps
-  optional int32 data_stall_rx_tput_thr_kbps = 7;
-
-  // Threshold of Tx packet error rate above which to trigger a data stall
-  // in percentage
-  optional int32 data_stall_tx_per_thr = 8;
-
-  // Threshold of CCA level above which to trigger a data stall in percentage
-  optional int32 data_stall_cca_level_thr = 9;
-}
-
-message WifiIsUnusableEvent {
-  enum TriggerType {
-    // Default/Invalid event
-    TYPE_UNKNOWN = 0;
-
-    // There is a data stall from tx failures
-    TYPE_DATA_STALL_BAD_TX = 1;
-
-    // There is a data stall from rx failures
-    TYPE_DATA_STALL_TX_WITHOUT_RX = 2;
-
-    // There is a data stall from both tx and rx failures
-    TYPE_DATA_STALL_BOTH = 3;
-
-    // Firmware generated an alert
-    TYPE_FIRMWARE_ALERT = 4;
-
-    // IP Manager lost reachability to network neighbors
-    TYPE_IP_REACHABILITY_LOST = 5;
-  }
-
-  // What event triggered WifiIsUnusableEvent.
-  optional TriggerType type = 1;
-
-  // The timestamp at which this event occurred.
-  // Measured in milliseconds that have elapsed since the device booted.
-  optional int64 start_time_millis = 2;
-
-  // NetworkAgent score of connected wifi.
-  // Defaults to -1 if the score was never set.
-  optional int32 last_score = 3 [default = -1];
-
-  // Delta of successfully transmitted (ACKed) unicast data packets
-  // between the last two WifiLinkLayerStats.
-  optional int64 tx_success_delta = 4;
-
-  // Delta of transmitted unicast data retry packets
-  // between the last two WifiLinkLayerStats.
-  optional int64 tx_retries_delta = 5;
-
-  // Delta of lost (not ACKed) transmitted unicast data packets
-  // between the last two WifiLinkLayerStats.
-  optional int64 tx_bad_delta = 6;
-
-  // Delta of received unicast data packets
-  // between the last two WifiLinkLayerStats.
-  optional int64 rx_success_delta = 7;
-
-  // Time in millisecond between the last two WifiLinkLayerStats.
-  optional int64 packet_update_time_delta = 8;
-
-  // The timestamp at which the last WifiLinkLayerStats was updated.
-  // Measured in milliseconds that have elapsed since the device booted.
-  optional int64 last_link_layer_stats_update_time = 9;
-
-  // Firmware alert code. Only valid when the event was triggered by a firmware alert, otherwise -1.
-  optional int32 firmware_alert_code = 10 [default = -1];
-
-  // NetworkAgent wifi usability score of connected wifi.
-  // Defaults to -1 if the score was never set.
-  optional int32 last_wifi_usability_score = 11 [default = -1];
-
-  // Prediction horizon (in second) of Wifi usability score provided by external
-  // system app
-  optional int32 last_prediction_horizon_sec = 12 [default = -1];
-
-  // Whether screen status is on when WifiIsUnusableEvent happens.
-  optional bool screen_on = 13 [default = false];
-}
-
-message PasspointProfileTypeCount {
-  enum EapMethod {
-    // Unknown Type
-    TYPE_UNKNOWN = 0;
-
-    // EAP_TLS (13)
-    TYPE_EAP_TLS = 1;
-
-    // EAP_TTLS (21)
-    TYPE_EAP_TTLS = 2;
-
-    // EAP_SIM (18)
-    TYPE_EAP_SIM = 3;
-
-    // EAP_AKA (23)
-    TYPE_EAP_AKA = 4;
-
-    // EAP_AKA_PRIME (50)
-    TYPE_EAP_AKA_PRIME = 5;
-  }
-
-  // Eap method type set in Passpoint profile
-  optional EapMethod eap_method_type = 1;
-
-  // Num of installed Passpoint profile with same eap method
-  optional int32 count = 2;
-}
-
-message WifiLinkLayerUsageStats {
-  // Total logging duration in ms.
-  optional int64 logging_duration_ms = 1;
-
-  // Total time the wifi radio is on in ms over the logging duration.
-  optional int64 radio_on_time_ms = 2;
-
-  // Total time the wifi radio is doing tx in ms over the logging duration.
-  optional int64 radio_tx_time_ms = 3;
-
-  // Total time the wifi radio is doing rx in ms over the logging duration.
-  optional int64 radio_rx_time_ms = 4;
-
-  // Total time the wifi radio is scanning in ms over the logging duration.
-  optional int64 radio_scan_time_ms = 5;
-
-  // Total time the wifi radio spent doing nan scans in ms over the logging duration.
-  optional int64 radio_nan_scan_time_ms = 6;
-
-  // Total time the wifi radio spent doing background scans in ms over the logging duration.
-  optional int64 radio_background_scan_time_ms = 7;
-
-  // Total time the wifi radio spent doing roam scans in ms over the logging duration.
-  optional int64 radio_roam_scan_time_ms = 8;
-
-  // Total time the wifi radio spent doing pno scans in ms over the logging duration.
-  optional int64 radio_pno_scan_time_ms = 9;
-
-  // Total time the wifi radio spent doing hotspot 2.0 scans and GAS exchange
-  // in ms over the logging duration.
-  optional int64 radio_hs20_scan_time_ms = 10;
-}
-
-message WifiUsabilityStatsEntry {
-  // Status codes for link probe status
-  enum LinkProbeStatus {
-    // Link probe status is unknown
-    PROBE_STATUS_UNKNOWN = 0;
-
-    // Link probe is not triggered
-    PROBE_STATUS_NO_PROBE = 1;
-
-    // Link probe is triggered and the result is success
-    PROBE_STATUS_SUCCESS = 2;
-
-    // Link probe is triggered and the result is failure
-    PROBE_STATUS_FAILURE = 3;
-  }
-
-  // Codes for cellular data network type
-  enum CellularDataNetworkType {
-    // Unknown network
-    NETWORK_TYPE_UNKNOWN = 0;
-
-    // GSM network
-    NETWORK_TYPE_GSM = 1;
-
-    // CDMA network
-    NETWORK_TYPE_CDMA = 2;
-
-    // CDMA EVDO network
-    NETWORK_TYPE_EVDO_0 = 3;
-
-    // WCDMA network
-    NETWORK_TYPE_UMTS = 4;
-
-    // TDSCDMA network
-    NETWORK_TYPE_TD_SCDMA = 5;
-
-    // LTE network
-    NETWORK_TYPE_LTE = 6;
-
-    // NR network
-    NETWORK_TYPE_NR = 7;
-  }
-
-  // Absolute milliseconds from device boot when these stats were sampled
-  optional int64 time_stamp_ms = 1;
-
-  // The RSSI at the sample time
-  optional int32 rssi = 2;
-
-  // Link speed at the sample time in Mbps
-  optional int32 link_speed_mbps = 3;
-
-  // The total number of tx success counted from the last radio chip reset
-  optional int64 total_tx_success = 4;
-
-  // The total number of MPDU data packet retries counted from the last radio chip reset
-  optional int64 total_tx_retries = 5;
-
-  // The total number of tx bad counted from the last radio chip reset
-  optional int64 total_tx_bad = 6;
-
-  // The total number of rx success counted from the last radio chip reset
-  optional int64 total_rx_success = 7;
-
-  // The total time the wifi radio is on in ms counted from the last radio chip reset
-  optional int64 total_radio_on_time_ms = 8;
-
-  // The total time the wifi radio is doing tx in ms counted from the last radio chip reset
-  optional int64 total_radio_tx_time_ms = 9;
-
-  // The total time the wifi radio is doing rx in ms counted from the last radio chip reset
-  optional int64 total_radio_rx_time_ms = 10;
-
-  // The total time spent on all types of scans in ms counted from the last radio chip reset
-  optional int64 total_scan_time_ms = 11;
-
-  // The total time spent on nan scans in ms counted from the last radio chip reset
-  optional int64 total_nan_scan_time_ms = 12;
-
-  // The total time spent on background scans in ms counted from the last radio chip reset
-  optional int64 total_background_scan_time_ms = 13;
-
-  // The total time spent on roam scans in ms counted from the last radio chip reset
-  optional int64 total_roam_scan_time_ms = 14;
-
-  // The total time spent on pno scans in ms counted from the last radio chip reset
-  optional int64 total_pno_scan_time_ms = 15;
-
-  // The total time spent on hotspot2.0 scans and GAS exchange in ms counted from the last radio
-  // chip reset
-  optional int64 total_hotspot_2_scan_time_ms = 16;
-
-  // Internal framework Wifi score
-  optional int32 wifi_score = 17;
-
-  // Wifi usability score provided by external system app
-  optional int32 wifi_usability_score = 18;
-
-  // Sequence number from external system app to framework
-  optional int32 seq_num_to_framework = 19;
-
-  // The total time CCA is on busy status on the current frequency in ms
-  // counted from the last radio chip reset
-  optional int64 total_cca_busy_freq_time_ms = 20;
-
-  // The total radio on time of the current frequency from the last radio
-  // chip reset
-  optional int64 total_radio_on_freq_time_ms = 21;
-
-  // The total number of beacons received from the last radio chip reset
-  optional int64 total_beacon_rx = 22;
-
-  // Prediction horizon (in second) of Wifi usability score provided by external
-  // system app
-  optional int32 prediction_horizon_sec = 23;
-
-  // The link probe status since last stats update
-  optional LinkProbeStatus probe_status_since_last_update = 24;
-
-  // The elapsed time of the most recent link probe since last stats update;
-  optional int32 probe_elapsed_time_since_last_update_ms = 25;
-
-  // The MCS rate of the most recent link probe since last stats update
-  optional int32 probe_mcs_rate_since_last_update = 26;
-
-  // Rx link speed at the sample time in Mbps
-  optional int32 rx_link_speed_mbps = 27;
-
-  // Sequence number generated by framework
-  optional int32 seq_num_inside_framework = 28;
-
-  // Whether current entry is for the same BSSID on the same frequency compared
-  // to last entry
-  optional bool is_same_bssid_and_freq = 29;
-
-  // Cellular data network type currently in use on the device for data transmission
-  optional CellularDataNetworkType cellular_data_network_type = 30;
-
-  // Cellular signal strength in dBm, NR: CsiRsrp, LTE: Rsrp, WCDMA/TDSCDMA: Rscp,
-  // CDMA: Rssi, EVDO: Rssi, GSM: Rssi
-  optional int32 cellular_signal_strength_dbm = 31;
-
-  // Cellular signal strength in dB, NR: CsiSinr, LTE: Rsrq, WCDMA: EcNo, TDSCDMA: invalid,
-  // CDMA: Ecio, EVDO: SNR, GSM: invalid */
-  optional int32 cellular_signal_strength_db = 32;
-
-  // Whether the primary registered cell of current entry is same as that of previous entry
-  optional bool is_same_registered_cell = 33;
-
-  // The device mobility state
-  optional DeviceMobilityStatePnoScanStats.DeviceMobilityState
-          device_mobility_state = 34;
-}
-
-message WifiUsabilityStats {
-  enum Label {
-    // Default label
-    LABEL_UNKNOWN = 0;
-
-    // Wifi is usable
-    LABEL_GOOD = 1;
-
-    // Wifi is unusable
-    LABEL_BAD = 2;
-  }
-
-  enum UsabilityStatsTriggerType {
-    // Default/Invalid event
-    TYPE_UNKNOWN = 0;
-
-    // There is a data stall from tx failures
-    TYPE_DATA_STALL_BAD_TX = 1;
-
-    // There is a data stall from rx failures
-    TYPE_DATA_STALL_TX_WITHOUT_RX = 2;
-
-    // There is a data stall from both tx and rx failures
-    TYPE_DATA_STALL_BOTH = 3;
-
-    // Firmware generated an alert
-    TYPE_FIRMWARE_ALERT = 4;
-
-    // IP Manager lost reachability to network neighbors
-    TYPE_IP_REACHABILITY_LOST = 5;
-  }
-
-  // The current wifi usability state
-  optional Label label = 1;
-
-  // The list of timestamped wifi usability stats
-  repeated WifiUsabilityStatsEntry stats = 2;
-
-  // What event triggered WifiUsabilityStats.
-  optional UsabilityStatsTriggerType trigger_type = 3;
-
-  // Firmware alert code. Only valid when the stats was triggered by a firmware
-  // alert, otherwise -1.
-  optional int32 firmware_alert_code = 4 [default = -1];
-
-  // Absolute milliseconds from device boot when these stats were sampled
-  optional int64 time_stamp_ms = 5;
-}
-
-message DeviceMobilityStatePnoScanStats {
-  // see WifiManager.DEVICE_MOBILITY_STATE_* constants
-  enum DeviceMobilityState {
-    // Unknown mobility
-    UNKNOWN = 0;
-
-    // High movement
-    HIGH_MVMT = 1;
-
-    // Low movement
-    LOW_MVMT = 2;
-
-    // Stationary
-    STATIONARY = 3;
-  }
-
-  // The device mobility state
-  optional DeviceMobilityState device_mobility_state = 1;
-
-  // The number of times that this state was entered
-  optional int32 num_times_entered_state = 2;
-
-  // The total duration elapsed while in this mobility state, in ms
-  optional int64 total_duration_ms = 3;
-
-  // the total duration elapsed while in this mobility state with PNO scans running, in ms
-  optional int64 pno_duration_ms = 4;
-}
-
-// The information about the Wifi P2p events.
-message WifiP2pStats {
-
-  // Group event list tracking sessions and client counts in tethered mode.
-  repeated GroupEvent group_event = 1;
-
-  // Session information that gets logged for every Wifi P2p connection.
-  repeated P2pConnectionEvent connection_event = 2;
-
-  // Number of persistent group in the user profile.
-  optional int32 num_persistent_group = 3;
-
-  // Number of peer scan.
-  optional int32 num_total_peer_scans = 4;
-
-  // Number of service scan.
-  optional int32 num_total_service_scans = 5;
-}
-
-message P2pConnectionEvent {
-
-  enum ConnectionType {
-
-    // fresh new connection.
-    CONNECTION_FRESH = 0;
-
-    // reinvoke a group.
-    CONNECTION_REINVOKE = 1;
-
-    // create a group with the current device as the group owner locally.
-    CONNECTION_LOCAL = 2;
-
-    // create a group or join a group with config.
-    CONNECTION_FAST = 3;
-  }
-
-  enum ConnectivityLevelFailure {
-
-    // Failure is unknown.
-    CLF_UNKNOWN = 0;
-
-    // No failure.
-    CLF_NONE = 1;
-
-    // Timeout for current connecting request.
-    CLF_TIMEOUT = 2;
-
-    // The connecting request is canceled by the user.
-    CLF_CANCEL = 3;
-
-    // Provision discovery failure, e.g. no pin code, timeout, rejected by the peer.
-    CLF_PROV_DISC_FAIL = 4;
-
-    // Invitation failure, e.g. rejected by the peer.
-    CLF_INVITATION_FAIL = 5;
-
-    // Incoming request is rejected by the user.
-    CLF_USER_REJECT = 6;
-
-    // New connection request is issued before ending previous connecting request.
-    CLF_NEW_CONNECTION_ATTEMPT = 7;
-  }
-
-  // WPS method.
-  enum WpsMethod {
-    // WPS is skipped for Group Reinvoke.
-    WPS_NA = -1;
-
-    // Push button configuration.
-    WPS_PBC = 0;
-
-    // Display pin method configuration - pin is generated and displayed on device.
-    WPS_DISPLAY = 1;
-
-    // Keypad pin method configuration - pin is entered on device.
-    WPS_KEYPAD = 2;
-
-    // Label pin method configuration - pin is labelled on device.
-    WPS_LABEL = 3;
-  }
-
-  // Start time of the connection.
-  optional int64 start_time_millis = 1;
-
-  // Type of the connection.
-  optional ConnectionType connection_type = 2;
-
-  // WPS method.
-  optional WpsMethod wps_method = 3 [default = WPS_NA];
-
-  // Duration to connect.
-  optional int32 duration_taken_to_connect_millis = 4;
-
-  // Failures that happen at the connectivity layer.
-  optional ConnectivityLevelFailure connectivity_level_failure_code = 5;
-}
-
-// GroupEvent tracking group information from GroupStarted to GroupRemoved.
-message GroupEvent {
-
-  enum GroupRole {
-
-    GROUP_OWNER = 0;
-
-    GROUP_CLIENT = 1;
-  }
-
-  // The ID of network in supplicant for this group.
-  optional int32 net_id = 1;
-
-  // Start time of the group.
-  optional int64 start_time_millis = 2;
-
-  // Channel frequency used for Group.
-  optional int32 channel_frequency = 3;
-
-  // Is group owner or group client.
-  optional GroupRole group_role = 5;
-
-  // Number of connected clients.
-  optional int32 num_connected_clients = 6;
-
-  // Cumulative number of connected clients.
-  optional int32 num_cumulative_clients = 7;
-
-  // The session duration.
-  optional int32 session_duration_millis = 8;
-
-  // The idle duration. A group without any client is in idle.
-  optional int32 idle_duration_millis = 9;
-}
-
-// Easy Connect (DPP)
-message WifiDppLog {
-  reserved 6;
-
-  // Number of Configurator-Initiator requests
-  optional int32 num_dpp_configurator_initiator_requests = 1;
-
-  // Number of Enrollee-Initiator requests
-  optional int32 num_dpp_enrollee_initiator_requests = 2;
-
-  // Easy Connect (DPP) Enrollee success
-  optional int32 num_dpp_enrollee_success = 3;
-
-  // Easy Connect (DPP) Configurator success code bucket
-  repeated DppConfiguratorSuccessStatusHistogramBucket dpp_configurator_success_code = 4;
-
-  // Easy Connect (DPP) failure code bucket
-  repeated DppFailureStatusHistogramBucket dpp_failure_code = 5;
-
-  // Easy Connect (DPP) operation time bucket
-  repeated HistogramBucketInt32 dpp_operation_time = 7;
-
-  // Histogram bucket for Wi-Fi DPP configurator success
-  message DppConfiguratorSuccessStatusHistogramBucket {
-    // status type defining the bucket
-    optional DppConfiguratorSuccessCode dpp_status_type = 1;
-
-    // number of samples in the bucket
-    optional int32 count = 2;
-  }
-
-  // Histogram bucket for Wi-Fi DPP failures
-  message DppFailureStatusHistogramBucket {
-    // status type defining the bucket
-    optional DppFailureCode dpp_status_type = 1;
-
-    // number of samples in the bucket
-    optional int32 count = 2;
-  }
-
-  enum DppConfiguratorSuccessCode {
-    // Unknown success code
-    EASY_CONNECT_EVENT_SUCCESS_UNKNOWN = 0;
-
-    // Easy Connect Configurator success event: Configuration sent to enrollee
-    EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT = 1;
-  }
-
-  enum DppFailureCode {
-    // Unknown failure
-    EASY_CONNECT_EVENT_FAILURE_UNKNOWN = 0;
-
-    // Easy Connect Failure event: Scanned QR code is either not a Easy Connect URI, or the Easy
-    // Connect URI has errors.
-    EASY_CONNECT_EVENT_FAILURE_INVALID_URI = 1;
-
-    // Easy Connect Failure event: Bootstrapping/Authentication initialization process failure.
-    EASY_CONNECT_EVENT_FAILURE_AUTHENTICATION = 2;
-
-    // Easy Connect Failure event: Both devices are implementing the same role and are
-    // incompatible.
-    EASY_CONNECT_EVENT_FAILURE_NOT_COMPATIBLE = 3;
-
-    // Easy Connect Failure event: Configuration process has failed due to malformed message.
-    EASY_CONNECT_EVENT_FAILURE_CONFIGURATION = 4;
-
-    // Easy Connect Failure event: Easy Connect request while in another Easy Connect exchange.
-    EASY_CONNECT_EVENT_FAILURE_BUSY = 5;
-
-    // Easy Connect Failure event: No response from the peer.
-    EASY_CONNECT_EVENT_FAILURE_TIMEOUT = 6;
-
-    // Easy Connect Failure event: General protocol failure.
-    EASY_CONNECT_EVENT_FAILURE_GENERIC = 7;
-
-    // Easy Connect Failure event: Feature or option is not supported.
-    EASY_CONNECT_EVENT_FAILURE_NOT_SUPPORTED = 8;
-
-    // Easy Connect Failure event: Invalid network provided to Easy Connect configurator.
-    // Network must either be WPA3-Personal (SAE) or WPA2-Personal (PSK).
-    EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK = 9;
-  }
-}
-
-// WifiConfigStore read/write metrics.
-message WifiConfigStoreIO {
-  // Histogram of config store read durations.
-  repeated DurationBucket read_durations = 1;
-
-  // Histogram of config store write durations.
-  repeated DurationBucket write_durations = 2;
-
-  // Total Number of instances of write/read duration in this duration bucket.
-  message DurationBucket {
-    // Bucket covers duration : [range_start_ms, range_end_ms)
-    // The (inclusive) lower bound of read/write duration represented by this bucket
-    optional int32 range_start_ms = 1;
-
-    // The (exclusive) upper bound of read/write duration represented by this bucket
-    optional int32 range_end_ms = 2;
-
-    // Number of read/write durations that fit into this bucket
-    optional int32 count = 3;
-  }
-}
-
-// Histogram bucket counting with int32. Range is [start, end)
-message HistogramBucketInt32 {
-  // lower range of the bucket (inclusive)
-  optional int32 start = 1;
-
-  // upper range of the bucket (exclusive)
-  optional int32 end = 2;
-
-  // number of samples in the bucket
-  optional int32 count = 3;
-}
-
-// Counts occurrences of a int32 key
-message Int32Count {
-  // the key
-  optional int32 key = 1;
-
-  // the count
-  optional int32 count = 2;
-}
-
-message LinkProbeStats {
-  enum LinkProbeFailureReason {
-    // unknown reason
-    LINK_PROBE_FAILURE_REASON_UNKNOWN = 0;
-
-    // Specified MCS rate when it is unsupported by the driver.
-    LINK_PROBE_FAILURE_REASON_MCS_UNSUPPORTED = 1;
-
-    // Driver reported that no ACK was received for the transmitted probe.
-    LINK_PROBE_FAILURE_REASON_NO_ACK = 2;
-
-    // Driver failed to report on the status of the transmitted probe within the timeout.
-    LINK_PROBE_FAILURE_REASON_TIMEOUT = 3;
-
-    // An existing link probe is in progress.
-    LINK_PROBE_FAILURE_REASON_ALREADY_STARTED = 4;
-  }
-
-  // Counts the number of failures for each failure reason.
-  message LinkProbeFailureReasonCount {
-    // The failure reason.
-    optional LinkProbeFailureReason failure_reason = 1;
-
-    // The number of occurrences for this failure reason.
-    optional int32 count = 2;
-  }
-
-  // Counts the number of link probes for each experiment.
-  message ExperimentProbeCounts {
-    // The experiment ID.
-    optional string experiment_id = 1;
-
-    // The number of link probes triggered for this experiment.
-    optional int32 probe_count = 2;
-  }
-
-  // Counts the occurrences of RSSI values when a link probe succeeds.
-  repeated Int32Count success_rssi_counts = 1;
-
-  // Counts the occurrences of RSSI values when a link probe fails.
-  repeated Int32Count failure_rssi_counts = 2;
-
-  // Counts the occurrences of Link Speed values when a link probe succeeds.
-  repeated Int32Count success_link_speed_counts = 3;
-
-  // Counts the occurrences of Link Speed values when a link probe fails.
-  repeated Int32Count failure_link_speed_counts = 4;
-
-  // Histogram for the number of seconds since the last TX success when a link probe succeeds.
-  repeated HistogramBucketInt32 success_seconds_since_last_tx_success_histogram = 5;
-
-  // Histogram for the number of seconds since the last TX success when a link probe fails.
-  repeated HistogramBucketInt32 failure_seconds_since_last_tx_success_histogram = 6;
-
-  // Histogram for the elapsed time of successful link probes, in ms.
-  repeated HistogramBucketInt32 success_elapsed_time_ms_histogram = 7;
-
-  // Counts the occurrences of error codes for failed link probes.
-  repeated LinkProbeFailureReasonCount failure_reason_counts = 8;
-
-  // Counts the number of link probes for each experiment.
-  repeated ExperimentProbeCounts experiment_probe_counts = 9;
-}
-
-// Stores the decisions that were made by a experiment when compared against another experiment
-message NetworkSelectionExperimentDecisions {
-  // the id of one experiment
-  optional int32 experiment1_id = 1;
-
-  // the id of the other experiment
-  optional int32 experiment2_id = 2;
-
-  // Counts occurrences of the number of network choices there were when experiment1 makes the
-  // same network selection as experiment2.
-  // The keys are the number of network choices, and the values are the number of occurrences of
-  // this number of network choices when exp1 and exp2 make the same network selection.
-  repeated Int32Count same_selection_num_choices_counter = 3;
-
-  // Counts occurrences of the number of network choices there were when experiment1 makes the
-  // same network selection as experiment2.
-  // The keys are the number of network choices, and the values are the number of occurrences of
-  // this number of network choices when exp1 and exp2 make different network selections.
-  // Note that it is possible for the network selection to be different even when there only exists
-  // a single network choice, since choosing not to connect to that network is a valid choice.
-  repeated Int32Count different_selection_num_choices_counter = 4;
-}
-
-// NetworkRequest API metrics.
-message WifiNetworkRequestApiLog {
-  // Number of requests via this API surface.
-  optional int32 num_request = 1;
-
-  // Histogram of requests via this API surface to number of networks matched in scan results.
-  repeated HistogramBucketInt32 network_match_size_histogram = 2;
-
-  // Number of successful network connection from this API.
-  optional int32 num_connect_success = 3;
-
-  // Number of requests via this API surface that bypassed user approval.
-  optional int32 num_user_approval_bypass = 4;
-
-  // Number of requests via this API surface that was rejected by the user.
-  optional int32 num_user_reject = 5;
-
-  // Number of unique apps using this API surface.
-  optional int32 num_apps = 6;
-}
-
-// NetworkSuggestion API metrics.
-message WifiNetworkSuggestionApiLog {
-  // Number of modifications to their suggestions by apps.
-  optional int32 num_modification = 1;
-
-  // Number of successful network connection from app suggestions.
-  optional int32 num_connect_success = 2;
-
-  // Number of network connection failures from app suggestions.
-  optional int32 num_connect_failure = 3;
-
-  // Histogram for size of the network lists provided by various apps on the device.
-  repeated HistogramBucketInt32 network_list_size_histogram = 4;
-}
-
-// WifiLock metrics
-message WifiLockStats {
-    // Amount of time wifi is actively in HIGH_PERF mode (ms)
-    // This means the lock takes effect and the device takes the actions required for this mode
-    optional int64 high_perf_active_time_ms = 1;
-
-    // Amount of time wifi is actively in LOW_LATENCY mode (ms)
-    // This means the lock takes effect and the device takes the actions required for this mode
-    optional int64 low_latency_active_time_ms = 2;
-
-    // Histogram of HIGH_PERF lock acquisition duration (seconds)
-    // Note that acquiring the lock does not necessarily mean that device is actively in that mode
-    repeated HistogramBucketInt32 high_perf_lock_acq_duration_sec_histogram = 3;
-
-    // Histogram of LOW_LATENCY lock acquisition duration (seconds)
-    // Note that acquiring the lock does not necessarily mean that device is actively in that mode
-    repeated HistogramBucketInt32 low_latency_lock_acq_duration_sec_histogram = 4;
-
-    // Histogram of HIGH_PERF active session duration (seconds)
-    // This means the lock takes effect and the device takes the actions required for this mode
-    repeated HistogramBucketInt32 high_perf_active_session_duration_sec_histogram = 5;
-
-    // Histogram of LOW_LATENCY active session duration (seconds)
-    // This means the lock takes effect and the device takes the actions required for this mode
-    repeated HistogramBucketInt32 low_latency_active_session_duration_sec_histogram = 6;
-}
-
-// Stats on number of times Wi-Fi is turned on/off though the WifiManager#setWifiEnabled API
-message WifiToggleStats {
-  // Number of time Wi-Fi is turned on by privileged apps
-  optional int32 num_toggle_on_privileged = 1;
-
-  // Number of time Wi-Fi is turned off by privileged apps
-  optional int32 num_toggle_off_privileged = 2;
-
-  // Number of time Wi-Fi is turned on by normal apps
-  optional int32 num_toggle_on_normal = 3;
-
-  // Number of time Wi-Fi is turned off by normal apps
-  optional int32 num_toggle_off_normal = 4;
-}
-
-// Information about the Passpoint provision metrics.
-message PasspointProvisionStats {
-  enum ProvisionFailureCode {
-    // provisioning failure for unknown reason.
-    OSU_FAILURE_UNKNOWN = 0;
-
-    // The reason code for Provisioning Failure due to connection failure to OSU AP.
-    OSU_FAILURE_AP_CONNECTION = 1;
-
-    // The reason code for invalid server URL address.
-    OSU_FAILURE_SERVER_URL_INVALID = 2;
-
-    // The reason code for provisioning failure due to connection failure to the server.
-    OSU_FAILURE_SERVER_CONNECTION = 3;
-
-    // The reason code for provisioning failure due to invalid server certificate.
-    OSU_FAILURE_SERVER_VALIDATION = 4;
-
-    // The reason code for provisioning failure due to invalid service provider.
-    OSU_FAILURE_SERVICE_PROVIDER_VERIFICATION = 5;
-
-    // The reason code for provisioning failure when a provisioning flow is aborted.
-    OSU_FAILURE_PROVISIONING_ABORTED = 6;
-
-    // The reason code for provisioning failure when a provisioning flow is not possible.
-    OSU_FAILURE_PROVISIONING_NOT_AVAILABLE = 7;
-
-    // The reason code for provisioning failure due to invalid web url format for an OSU web page.
-    OSU_FAILURE_INVALID_URL_FORMAT_FOR_OSU = 8;
-
-    // The reason code for provisioning failure when a command received is not the expected command
-    // type.
-    OSU_FAILURE_UNEXPECTED_COMMAND_TYPE = 9;
-
-    // The reason code for provisioning failure when a SOAP message is not the expected message
-    // type.
-    OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_TYPE = 10;
-
-    // The reason code for provisioning failure when a SOAP message exchange fails.
-    OSU_FAILURE_SOAP_MESSAGE_EXCHANGE = 11;
-
-    // The reason code for provisioning failure when a redirect listener fails to start.
-    OSU_FAILURE_START_REDIRECT_LISTENER = 12;
-
-    // The reason code for provisioning failure when a redirect listener timed out to receive a HTTP
-    // redirect response.
-    OSU_FAILURE_TIMED_OUT_REDIRECT_LISTENER = 13;
-
-    // The reason code for provisioning failure when there is no OSU activity to listen to intent.
-    OSU_FAILURE_NO_OSU_ACTIVITY_FOUND = 14;
-
-    // The reason code for provisioning failure when the status of a SOAP message is not the
-    // expected message status.
-    OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS = 15;
-
-    // The reason code for provisioning failure when there is no PPS MO.
-    OSU_FAILURE_NO_PPS_MO = 16;
-
-    // The reason code for provisioning failure when there is no AAAServerTrustRoot node in a PPS
-    // MO.
-    OSU_FAILURE_NO_AAA_SERVER_TRUST_ROOT_NODE = 17;
-
-    // The reason code for provisioning failure when there is no TrustRoot node for remediation
-    // server in a PPS MO.
-    OSU_FAILURE_NO_REMEDIATION_SERVER_TRUST_ROOT_NODE = 18;
-
-    // The reason code for provisioning failure when there is no TrustRoot node for policy server in
-    // a PPS MO.
-    OSU_FAILURE_NO_POLICY_SERVER_TRUST_ROOT_NODE = 19;
-
-    // The reason code for provisioning failure when failing to retrieve trust root certificates
-    // used for validating server certificate for AAA, Remediation and Policy server.
-    OSU_FAILURE_RETRIEVE_TRUST_ROOT_CERTIFICATES = 20;
-
-    // The reason code for provisioning failure when there is no trust root certificate for AAA
-    // server.
-    OSU_FAILURE_NO_AAA_TRUST_ROOT_CERTIFICATE = 21;
-
-    // The reason code for provisioning failure when a {@link PasspointConfiguration} is failed to
-    // install.
-    OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION = 22;
-
-    // The reason code for provisioning failure when an {@link OsuProvider} is not found for
-    // provisioning.
-    OSU_FAILURE_OSU_PROVIDER_NOT_FOUND = 23;
-  }
-
-  // Number of passpoint provisioning success
-  optional int32 num_provision_success = 1;
-
-  // Count for passpoint provisioning failure
-  repeated ProvisionFailureCount provision_failure_count = 2;
-
-  // Number of occurrences of a specific passpoint provision failure code
-  message ProvisionFailureCount {
-    // Failure code
-    optional ProvisionFailureCode failure_code = 1;
-
-    // Number of failure for the failure_code.
-    optional int32 count = 2;
-  }
-}
diff --git a/services/Android.bp b/services/Android.bp
index 60dd895..6953e86 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -47,11 +47,6 @@
         "compat-changeid-annotation-processor",
     ],
 
-    required: [
-      // Required by services.backup
-      "BackupEncryption",
-    ],
-
     // Uncomment to enable output of certain warnings (deprecated, unchecked)
     //javacflags: ["-Xlint"],
 
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 68e11df32..6f43529 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -67,8 +67,6 @@
 import android.os.UserManager;
 import android.os.UserManagerInternal;
 import android.provider.Settings;
-import android.provider.SettingsStringUtil;
-import android.provider.SettingsStringUtil.ComponentNameSet;
 import android.provider.SettingsStringUtil.SettingStringHelper;
 import android.text.TextUtils;
 import android.text.TextUtils.SimpleStringSplitter;
@@ -2219,12 +2217,12 @@
      * Enables accessibility service specified by {@param componentName} for the {@param userId}.
      */
     private void enableAccessibilityServiceLocked(ComponentName componentName, int userId) {
-        final SettingStringHelper setting =
-                new SettingStringHelper(
-                        mContext.getContentResolver(),
-                        Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
-                        userId);
-        setting.write(ComponentNameSet.add(setting.read(), componentName));
+        mTempComponentNameSet.clear();
+        readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                userId, mTempComponentNameSet);
+        mTempComponentNameSet.add(componentName);
+        persistComponentNamesToSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                mTempComponentNameSet, userId);
 
         AccessibilityUserState userState = getUserStateLocked(userId);
         if (userState.mEnabledServices.add(componentName)) {
@@ -2236,12 +2234,12 @@
      * Disables accessibility service specified by {@param componentName} for the {@param userId}.
      */
     private void disableAccessibilityServiceLocked(ComponentName componentName, int userId) {
-        final SettingsStringUtil.SettingStringHelper setting =
-                new SettingStringHelper(
-                        mContext.getContentResolver(),
-                        Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
-                        userId);
-        setting.write(ComponentNameSet.remove(setting.read(), componentName));
+        mTempComponentNameSet.clear();
+        readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                userId, mTempComponentNameSet);
+        mTempComponentNameSet.remove(componentName);
+        persistComponentNamesToSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                mTempComponentNameSet, userId);
 
         AccessibilityUserState userState = getUserStateLocked(userId);
         if (userState.mEnabledServices.remove(componentName)) {
diff --git a/services/art-profile b/services/art-profile
index 8b911a2..a0338d5 100644
--- a/services/art-profile
+++ b/services/art-profile
@@ -21148,7 +21148,6 @@
 HPLcom/android/server/wm/RemoteAnimationController;->lambda$goodToGo$1$RemoteAnimationController([Landroid/view/RemoteAnimationTarget;[Landroid/view/RemoteAnimationTarget;)V
 HPLcom/android/server/wm/RunningTasks;->getTasks(ILjava/util/List;IILjava/util/ArrayList;IZZLandroid/util/ArraySet;)V
 HPLcom/android/server/wm/SplashScreenStartingData;->createStartingSurface(Lcom/android/server/wm/ActivityRecord;)Lcom/android/server/policy/WindowManagerPolicy$StartingSurface;
-HPLcom/android/server/wm/SurfaceAnimator$Animatable;->shouldDeferAnimationFinish(Ljava/lang/Runnable;)Z
 HPLcom/android/server/wm/SurfaceAnimator;->lambda$getFinishedCallback$0$SurfaceAnimator(Lcom/android/server/wm/AnimationAdapter;Ljava/lang/Runnable;)V
 HPLcom/android/server/wm/Task;->positionChildAt(ILcom/android/server/wm/ActivityRecord;Z)V
 HPLcom/android/server/wm/TaskRecord;->handlesOrientationChangeFromDescendant()Z
@@ -21191,7 +21190,6 @@
 HPLcom/android/server/wm/RemoteAnimationController;->createRemoteAnimationRecord(Lcom/android/server/wm/ActivityRecord;Landroid/graphics/Point;Landroid/graphics/Rect;Landroid/graphics/Rect;)Lcom/android/server/wm/RemoteAnimationController$RemoteAnimationRecord;
 HPLcom/android/server/wm/RemoteAnimationController;->linkToDeathOfRunner()V
 HPLcom/android/server/wm/RemoteAnimationController;->writeStartDebugStatement()V
-HPLcom/android/server/wm/SurfaceAnimator$Animatable;->shouldDeferAnimationFinish(Ljava/lang/Runnable;)Z
 HPLcom/android/server/wm/TaskRecord;->setMinDimensions(Landroid/content/pm/ActivityInfo;)V
 HPLcom/android/server/wm/WallpaperAnimationAdapter;->startWallpaperAnimations(Lcom/android/server/wm/WindowManagerService;JJLjava/util/function/Consumer;Ljava/util/ArrayList;)[Landroid/view/RemoteAnimationTarget;
 HPLcom/android/server/wm/WindowStateAnimator;->finishDrawingLocked(Landroid/view/SurfaceControl$Transaction;)Z
@@ -21206,13 +21204,152 @@
 HPLcom/android/server/wm/AnimationAdapter;->writeToProto(Landroid/util/proto/ProtoOutputStream;J)V
 HPLcom/android/server/wm/RemoteAnimationController$RemoteAnimationAdapterWrapper;->dump(Ljava/io/PrintWriter;Ljava/lang/String;)V
 HPLcom/android/server/wm/RemoteAnimationController$RemoteAnimationRecord;-><init>(Lcom/android/server/wm/RemoteAnimationController;Lcom/android/server/wm/ActivityRecord;Landroid/graphics/Point;Landroid/graphics/Rect;Landroid/graphics/Rect;)V
-HPLcom/android/server/wm/SurfaceAnimator$Animatable;->shouldDeferAnimationFinish(Ljava/lang/Runnable;)Z
 HPLcom/android/server/wm/WindowProcessController;->setBoundClientUids(Landroid/util/ArraySet;)V
 HPLcom/google/android/startop/iorap/IorapForwardingService$AppLaunchObserver;->lambda$onActivityLaunched$2$IorapForwardingService$AppLaunchObserver([BILcom/google/android/startop/iorap/IIorap;)V
 HPLcom/google/android/startop/iorap/IorapForwardingService$AppLaunchObserver;->lambda$onActivityLaunchFinished$4$IorapForwardingService$AppLaunchObserver([BJLcom/google/android/startop/iorap/IIorap;)V
 HPLcom/google/android/startop/iorap/IorapForwardingService$AppLaunchObserver;->lambda$onIntentStarted$0$IorapForwardingService$AppLaunchObserver(Landroid/content/Intent;JLcom/google/android/startop/iorap/IIorap;)V
 HPLcom/android/server/statusbar/StatusBarManagerService;->updateUiVisibilityLocked(IIIIILandroid/graphics/Rect;Landroid/graphics/Rect;Z)V
 HPLcom/android/server/wm/AnimationAdapter;->writeToProto(Landroid/util/proto/ProtoOutputStream;J)V
-HPLcom/android/server/wm/SurfaceAnimator$Animatable;->shouldDeferAnimationFinish(Ljava/lang/Runnable;)Z
 HPLcom/google/android/startop/iorap/IIorap$Stub$Proxy;->onAppLaunchEvent(Lcom/google/android/startop/iorap/RequestId;Lcom/google/android/startop/iorap/AppLaunchEvent;)V
 HPLcom/google/android/startop/iorap/RequestId;->nextValueForSequence()Lcom/google/android/startop/iorap/RequestId;
+HPLcom/android/server/AlarmManagerService;->decrementAlarmCount(II)V
+HPLcom/android/server/am/ActivityManagerService$4;->newArray(I)[Landroid/content/IntentFilter;
+HPLcom/android/server/am/ActivityManagerService$PidMap;->remove(Lcom/android/server/am/ProcessRecord;)V
+HPLcom/android/server/am/ActivityManagerService;->updateOomAdjLocked(Ljava/lang/String;)V
+HPLcom/android/server/am/ActivityManagerShellCommand$1;-><init>(Lcom/android/server/am/ActivityManagerShellCommand;)V
+HPLcom/android/server/am/ActivityManagerShellCommand;-><init>(Lcom/android/server/am/ActivityManagerService;Z)V
+HPLcom/android/server/am/ActivityManagerShellCommand;->runStartActivity(Ljava/io/PrintWriter;)I
+HPLcom/android/server/am/HostingRecord;-><init>(Ljava/lang/String;Landroid/content/ComponentName;I)V
+HPLcom/android/server/am/PendingIntentController;->registerIntentSenderCancelListener(Landroid/content/IIntentSender;Lcom/android/internal/os/IResultReceiver;)V
+HPLcom/android/server/appprediction/-$$Lambda$AppPredictionManagerService$PredictionManagerServiceStub$vSY20eQq5y5FXrxhhqOTcEmezTs;-><init>(Landroid/app/prediction/AppPredictionSessionId;)V
+HPLcom/android/server/appprediction/-$$Lambda$RemoteAppPredictionService$9DCowUTEF8fYuBlWGxOmP5hTAWA;-><init>(Landroid/app/prediction/AppPredictionSessionId;)V
+HPLcom/android/server/appprediction/RemoteAppPredictionService;->lambda$requestPredictionUpdate$6(Landroid/app/prediction/AppPredictionSessionId;Landroid/service/appprediction/IPredictionService;)V
+HPLcom/android/server/autofill/-$$Lambda$AutofillManagerService$1$1-WNu3tTkxodB_LsZ7dGIlvrPN0;->visit(Ljava/lang/Object;)V
+HPLcom/android/server/autofill/ui/-$$Lambda$AutoFillUI$56AC3ykfo4h_e2LSjdkJ3XQn370;-><init>(Lcom/android/server/autofill/ui/AutoFillUI;Lcom/android/server/autofill/ui/AutoFillUI$AutoFillUiCallback;)V
+HPLcom/android/server/contentsuggestions/-$$Lambda$RemoteContentSuggestionsService$Enqw46SYVKFK9F2xX4qUcIu5_3I;->run(Landroid/os/IInterface;)V
+HPLcom/android/server/contentsuggestions/-$$Lambda$RemoteContentSuggestionsService$eoGnQ2MDLLnW1UBX6wxNE1VBLAk;->run(Landroid/os/IInterface;)V
+HPLcom/android/server/contentsuggestions/-$$Lambda$RemoteContentSuggestionsService$VKh1DoMPNSPjPfnVGdsInmxuqzc;->run(Landroid/os/IInterface;)V
+HPLcom/android/server/contentsuggestions/-$$Lambda$RemoteContentSuggestionsService$yUTbcaYlZCYTmagCkNJ3i2VCkY4;->run(Landroid/os/IInterface;)V
+HPLcom/android/server/contentsuggestions/RemoteContentSuggestionsService;->getServiceInterface(Landroid/os/IBinder;)Landroid/os/IInterface;
+HPLcom/android/server/display/AutomaticBrightnessController;->updateAutoBrightness(ZZ)V
+HPLcom/android/server/display/DisplayPowerController$BrightnessReason;->setModifier(I)V
+HPLcom/android/server/display/DisplayPowerController$BrightnessReason;->setReason(I)V
+HPLcom/android/server/display/DisplayPowerController$BrightnessReason;->toString(I)Ljava/lang/String;
+HPLcom/android/server/display/DisplayPowerController$BrightnessReason;->toString()Ljava/lang/String;
+HPLcom/android/server/media/projection/MediaProjectionManagerService$1;->onProcessDied(II)V
+HPLcom/android/server/net/NetworkPolicyManagerService;->removeUidStateUL(I)Z
+HPLcom/android/server/pm/permission/PermissionManagerService;->addOnPermissionsChangeListener(Landroid/permission/IOnPermissionsChangeListener;)V
+HPLcom/android/server/protolog/ProtoLogImpl;->getSingleInstance()Lcom/android/server/protolog/ProtoLogImpl;
+HPLcom/android/server/soundtrigger/SoundTriggerHelper$PowerSaveModeListener;-><init>(Lcom/android/server/soundtrigger/SoundTriggerHelper;)V
+HPLcom/android/server/statusbar/-$$Lambda$StatusBarManagerService$uF0ibEnnXe7Lxunxb98QQLJjgZM;->run()V
+HPLcom/android/server/statusbar/StatusBarManagerService$UiState;->setSystemUiState(IIILandroid/graphics/Rect;Landroid/graphics/Rect;Z)V
+HPLcom/android/server/statusbar/StatusBarManagerService$UiState;->systemUiStateEquals(IIILandroid/graphics/Rect;Landroid/graphics/Rect;Z)Z
+HPLcom/android/server/usage/UsageStatsDatabase;->filterStats(Lcom/android/server/usage/IntervalStats;)V
+HPLcom/android/server/VibratorService$VibrationInfo;-><init>(JLandroid/os/VibrationEffect;Landroid/os/VibrationEffect;Landroid/media/AudioAttributes;ILjava/lang/String;Ljava/lang/String;)V
+HPLcom/android/server/VibratorService;->getAppOpMode(Lcom/android/server/VibratorService$Vibration;)I
+HPLcom/android/server/VibratorService;->getCurrentIntensityLocked(Lcom/android/server/VibratorService$Vibration;)I
+HPLcom/android/server/VibratorService;->isAllowedToVibrateLocked(Lcom/android/server/VibratorService$Vibration;)Z
+HPLcom/android/server/VibratorService;->vibrate(ILjava/lang/String;Landroid/os/VibrationEffect;Landroid/media/AudioAttributes;Ljava/lang/String;Landroid/os/IBinder;)V
+HPLcom/android/server/wm/-$$Lambda$ActivityRecord$g49I60MBbnNkxHlgA-NR7ALwWTQ;->apply(Ljava/lang/Object;)Z
+HPLcom/android/server/wm/-$$Lambda$ActivityRecord$pBc6yUdDV5IrUd9vt6oCz6QzpiE;->accept(Ljava/lang/Object;)V
+HPLcom/android/server/wm/-$$Lambda$BEx3OWenCvYAaV5h_J2ZkZXhEcY;->accept(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
+HPLcom/android/server/wm/-$$Lambda$DisplayPolicy$Zbxkj4wIhcDki6VwBh1kWmSmxqM;-><init>(Lcom/android/server/wm/DisplayPolicy;IIILandroid/graphics/Rect;Landroid/graphics/Rect;ZLcom/android/server/wm/WindowState;I[Lcom/android/internal/view/AppearanceRegion;ZZ)V
+HPLcom/android/server/wm/-$$Lambda$DisplayPolicy$Zbxkj4wIhcDki6VwBh1kWmSmxqM;->run()V
+HPLcom/android/server/wm/-$$Lambda$TaskChangeNotificationController$UexNbaqPy0mc3VxTw2coCctHho8;->accept(Landroid/app/ITaskStackListener;Landroid/os/Message;)V
+HPLcom/android/server/wm/ActivityMetricsLogger;->allWindowsDrawn()Z
+HPLcom/android/server/wm/ActivityRecord;->createAnimationBoundsLayer(Landroid/view/SurfaceControl$Transaction;)Landroid/view/SurfaceControl;
+HPLcom/android/server/wm/ActivityRecord;->destroyed(Ljava/lang/String;)V
+HPLcom/android/server/wm/ActivityRecord;->forAllWindowsUnchecked(Lcom/android/internal/util/ToBooleanFunction;Z)Z
+HPLcom/android/server/wm/ActivityRecord;->getTopFullscreenWindow()Lcom/android/server/wm/WindowState;
+HPLcom/android/server/wm/ActivityRecord;->loadAnimation(Landroid/view/WindowManager$LayoutParams;IZZ)Landroid/view/animation/Animation;
+HPLcom/android/server/wm/ActivityRecord;->notifyAppStopped()V
+HPLcom/android/server/wm/ActivityRecord;->onFirstWindowDrawn(Lcom/android/server/wm/WindowState;Lcom/android/server/wm/WindowStateAnimator;)V
+HPLcom/android/server/wm/ActivityRecord;->onRemovedFromDisplay()V
+HPLcom/android/server/wm/ActivityRecord;->removeDeadWindows()V
+HPLcom/android/server/wm/ActivityRecord;->setClientHidden(Z)V
+HPLcom/android/server/wm/ActivityRecord;->stopFreezingScreenLocked(Z)V
+HPLcom/android/server/wm/ActivityStack;->removeTimeoutsForActivity(Lcom/android/server/wm/ActivityRecord;)V
+HPLcom/android/server/wm/ActivityStarter;->recycleTask(Lcom/android/server/wm/TaskRecord;Lcom/android/server/wm/ActivityRecord;Lcom/android/server/wm/ActivityRecord;[Lcom/android/server/wm/ActivityRecord;)I
+HPLcom/android/server/wm/ActivityTaskManagerService;->getTaskSnapshot(IZZ)Landroid/app/ActivityManager$TaskSnapshot;
+HPLcom/android/server/wm/AnimationAdapter;->writeToProto(Landroid/util/proto/ProtoOutputStream;J)V
+HPLcom/android/server/wm/DisplayContent;->getWindowCornerRadius()F
+HPLcom/android/server/wm/DisplayPolicy;->convertNonDecorInsetsToStableInsets(Landroid/graphics/Rect;I)V
+HPLcom/android/server/wm/DisplayPolicy;->getInsetsPolicy()Lcom/android/server/wm/InsetsPolicy;
+HPLcom/android/server/wm/DisplayPolicy;->updateLightStatusBarAppearanceLw(ILcom/android/server/wm/WindowState;Lcom/android/server/wm/WindowState;)I
+HPLcom/android/server/wm/InsetsPolicy;->getInsetsForDispatch(Lcom/android/server/wm/WindowState;)Landroid/view/InsetsState;
+HPLcom/android/server/wm/InsetsPolicy;->isHidden(I)Z
+HPLcom/android/server/wm/InsetsPolicy;->updateBarControlTarget(Lcom/android/server/wm/WindowState;)V
+HPLcom/android/server/wm/Task;->getTopFullscreenActivity()Lcom/android/server/wm/ActivityRecord;
+HPLcom/android/server/wm/TaskRecord;->removeTaskActivitiesLocked(Ljava/lang/String;)V
+HPLcom/android/server/wm/Task;->removeChild(Lcom/android/server/wm/ActivityRecord;)V
+HPLcom/android/server/wm/TaskSnapshotCache$CacheEntry;-><init>(Landroid/app/ActivityManager$TaskSnapshot;Lcom/android/server/wm/ActivityRecord;)V
+HPLcom/android/server/wm/TaskSnapshotController;->createTaskSnapshot(Lcom/android/server/wm/Task;F)Landroid/view/SurfaceControl$ScreenshotGraphicBuffer;
+HPLcom/android/server/wm/TaskSnapshotController;->findAppTokenForSnapshot(Lcom/android/server/wm/Task;)Lcom/android/server/wm/ActivityRecord;
+HPLcom/android/server/wm/TaskSnapshotPersister$DeleteWriteQueueItem;-><init>(Lcom/android/server/wm/TaskSnapshotPersister;II)V
+HPLcom/android/server/wm/TaskSnapshotPersister$StoreWriteQueueItem;-><init>(Lcom/android/server/wm/TaskSnapshotPersister;IILandroid/app/ActivityManager$TaskSnapshot;)V
+HPLcom/android/server/wm/TaskSnapshotPersister$StoreWriteQueueItem;->onQueuedLocked()V
+HPLcom/android/server/wm/WallpaperAnimationAdapter;->lambda$startWallpaperAnimations$0(JJLjava/util/function/Consumer;Ljava/util/ArrayList;Ljava/util/ArrayList;Lcom/android/server/wm/WallpaperWindowToken;)V
+HPLcom/android/server/wm/WallpaperAnimationAdapter;->startWallpaperAnimations(Lcom/android/server/wm/WindowManagerService;JJLjava/util/function/Consumer;Ljava/util/ArrayList;)[Landroid/view/RemoteAnimationTarget;
+HPLcom/android/server/wm/WindowAnimationSpec;->findTranslateAnimation(Landroid/view/animation/Animation;)Landroid/view/animation/TranslateAnimation;
+HPLcom/android/server/wm/WindowProcessControllerMap;->removeProcessFromUidMap(Lcom/android/server/wm/WindowProcessController;)V
+HPLcom/android/server/wm/WindowProcessController;->updateProcessInfo(ZZZ)V
+HPLcom/android/server/wm/WindowState$DeathRecipient;-><init>(Lcom/android/server/wm/WindowState;Lcom/android/server/wm/WindowState$1;)V
+HPLcom/android/server/wm/WindowState$WindowId;-><init>(Lcom/android/server/wm/WindowState;Lcom/android/server/wm/WindowState$1;)V
+HPLcom/google/android/startop/iorap/AppLaunchEvent$ActivityLaunched;->writeToParcelImpl(Landroid/os/Parcel;I)V
+HPLcom/google/android/startop/iorap/AppLaunchEvent$ActivityLaunchFinished;->writeToParcelImpl(Landroid/os/Parcel;I)V
+HPLcom/google/android/startop/iorap/AppLaunchEvent$IntentStarted;->writeToParcelImpl(Landroid/os/Parcel;I)V
+HPLcom/google/android/startop/iorap/AppLaunchEvent;->getTypeIndex()I
+HPLcom/android/server/pm/PackageManagerService;->access$7600(Lcom/android/server/pm/PackageManagerService;Landroid/content/Intent;Ljava/lang/String;IIZI)Landroid/content/pm/ResolveInfo;
+HPLcom/android/server/pm/PackageManagerService;->access$8100(Lcom/android/server/pm/PackageManagerService;II)Z
+HPLcom/android/server/wm/ActivityRecord$Token;->access$100(Lcom/android/server/wm/ActivityRecord$Token;Lcom/android/server/wm/ActivityRecord;)V
+HPLcom/android/server/wm/RemoteAnimationController$RemoteAnimationAdapterWrapper;->access$000(Lcom/android/server/wm/RemoteAnimationController$RemoteAnimationAdapterWrapper;)Lcom/android/server/wm/SurfaceAnimator$OnAnimationFinishedCallback;
+HPLcom/android/server/wm/RemoteAnimationController$RemoteAnimationAdapterWrapper;->access$400(Lcom/android/server/wm/RemoteAnimationController$RemoteAnimationAdapterWrapper;)Landroid/graphics/Point;
+HPLcom/android/server/wm/RemoteAnimationController$RemoteAnimationAdapterWrapper;->access$500(Lcom/android/server/wm/RemoteAnimationController$RemoteAnimationAdapterWrapper;)Landroid/graphics/Rect;
+HPLcom/android/server/wm/RemoteAnimationController;->access$100(Lcom/android/server/wm/RemoteAnimationController;)V
+HPLcom/android/server/wm/RemoteAnimationController;->access$300(Lcom/android/server/wm/RemoteAnimationController;)Landroid/view/RemoteAnimationAdapter;
+HPLcom/android/server/wm/TaskPersister$TaskWriteQueueItem;->access$200(Lcom/android/server/wm/TaskPersister$TaskWriteQueueItem;)Lcom/android/server/wm/TaskRecord;
+HPLcom/android/server/wm/TaskPersister;->access$000(I)Ljava/io/File;
+HPLcom/android/server/wm/WindowContainer;->access$100(Lcom/android/server/wm/WindowContainer;)Landroid/util/Pools$SynchronizedPool;
+HPLcom/android/server/wm/WindowManagerService;->access$1600(Lcom/android/server/wm/WindowManagerService;Landroid/os/IBinder;)V
+HPLcom/android/server/pm/ShortcutUser;->logSharingShortcutStats(Lcom/android/internal/logging/MetricsLogger;)V
+HPLcom/android/server/statusbar/StatusBarManagerService;->lambda$topAppWindowChanged$1$StatusBarManagerService(IZZ)V
+HPLcom/android/server/wm/ActivityRecord$Token;->attach(Lcom/android/server/wm/ActivityRecord;)V
+HPLcom/android/server/wm/AnimationAdapter;->writeToProto(Landroid/util/proto/ProtoOutputStream;J)V
+HPLcom/android/server/wm/DisplayPolicy;->lambda$updateSystemUiVisibilityLw$10$DisplayPolicy(IIILandroid/graphics/Rect;Landroid/graphics/Rect;ZLcom/android/server/wm/WindowState;I[Lcom/android/internal/view/AppearanceRegion;ZZ)V
+HPLcom/android/server/wm/InsetsSourceProvider;->hasWindow()Z
+HPLcom/android/server/wm/InsetsStateController;->onBarControlTargetChanged(Lcom/android/server/wm/InsetsControlTarget;Lcom/android/server/wm/InsetsControlTarget;Lcom/android/server/wm/InsetsControlTarget;Lcom/android/server/wm/InsetsControlTarget;)V
+HPLcom/android/server/wm/InsetsStateController;->peekSourceProvider(I)Lcom/android/server/wm/InsetsSourceProvider;
+HPLcom/android/server/wm/TaskPersister$TaskWriteQueueItem;->access$200(Lcom/android/server/wm/TaskPersister$TaskWriteQueueItem;)Lcom/android/server/wm/TaskRecord;
+HPLcom/android/server/wm/WindowContainer;->access$100(Lcom/android/server/wm/WindowContainer;)Landroid/util/Pools$SynchronizedPool;
+HPLcom/android/server/-$$Lambda$AlarmManagerService$2$Eo-D98J-N9R2METkD-12gPs320c;-><init>(Lcom/android/server/AlarmManagerService$2;Landroid/app/IAlarmCompleteListener;)V
+HPLcom/android/server/AlarmManagerService;->access$100(Lcom/android/server/AlarmManagerService;)Lcom/android/server/AlarmManagerService$Injector;
+HPLcom/android/server/AlarmManagerService;->access$2102(Lcom/android/server/AlarmManagerService;J)J
+HPLcom/android/server/AlarmManagerService;->access$2202(Lcom/android/server/AlarmManagerService;J)J
+HPLcom/android/server/AlarmManagerService;->access$2300(Lcom/android/server/AlarmManagerService;)V
+HPLcom/android/server/AlarmManagerService;->access$2400(Lcom/android/server/AlarmManagerService;Lcom/android/server/AlarmManagerService$Alarm;)Z
+HPLcom/android/server/AlarmManagerService;->isExemptFromAppStandby(Lcom/android/server/AlarmManagerService$Alarm;)Z
+HPLcom/android/server/appwidget/AppWidgetServiceImpl$HostId;-><init>(IILjava/lang/String;)V
+HPLcom/android/server/content/ContentService$ObserverCall;->run()V
+HPLcom/android/server/statusbar/-$$Lambda$StatusBarManagerService$uF0ibEnnXe7Lxunxb98QQLJjgZM;-><init>(Lcom/android/server/statusbar/StatusBarManagerService;IZZ)V
+HPLcom/android/server/statusbar/StatusBarManagerService$1;->topAppWindowChanged(IZZ)V
+HPLcom/android/server/statusbar/StatusBarManagerService$UiState;->access$1600(Lcom/android/server/statusbar/StatusBarManagerService$UiState;Z)V
+HPLcom/android/server/statusbar/StatusBarManagerService$UiState;->access$1700(Lcom/android/server/statusbar/StatusBarManagerService$UiState;Z)V
+HPLcom/android/server/statusbar/StatusBarManagerService$UiState;->setFullscreen(Z)V
+HPLcom/android/server/statusbar/StatusBarManagerService$UiState;->setImmersive(Z)V
+HPLcom/android/server/statusbar/StatusBarManagerService;->access$600(Lcom/android/server/statusbar/StatusBarManagerService;IZZ)V
+HPLcom/android/server/statusbar/StatusBarManagerService;->enforceStatusBar()V
+HPLcom/android/server/statusbar/StatusBarManagerService;->getUiState(I)Lcom/android/server/statusbar/StatusBarManagerService$UiState;
+HPLcom/android/server/statusbar/StatusBarManagerService;->topAppWindowChanged(IZZ)V
+HPLcom/android/server/wm/InsetsStateController;->onControlFakeTargetChanged(ILcom/android/server/wm/InsetsControlTarget;)V
+HPLcom/android/server/wm/LocalAnimationAdapter$AnimationSpec;->writeToProto(Landroid/util/proto/ProtoOutputStream;J)V
+HPLcom/android/server/wm/LocalAnimationAdapter;->writeToProto(Landroid/util/proto/ProtoOutputStream;)V
+HPLcom/android/server/wm/PersisterQueue;->access$100(Lcom/android/server/wm/PersisterQueue;)Ljava/util/ArrayList;
+HPLcom/android/server/wm/PersisterQueue;->access$200(Lcom/android/server/wm/PersisterQueue;)Ljava/util/ArrayList;
+HPLcom/android/server/wm/PersisterQueue;->access$300(Lcom/android/server/wm/PersisterQueue;)V
+HPLcom/android/server/wm/TaskSnapshotPersister;->access$100(Lcom/android/server/wm/TaskSnapshotPersister;)Ljava/lang/Object;
+HPLcom/android/server/wm/TaskSnapshotPersister;->access$200(Lcom/android/server/wm/TaskSnapshotPersister;)Z
+HPLcom/android/server/wm/TaskSnapshotPersister;->access$300(Lcom/android/server/wm/TaskSnapshotPersister;)Ljava/util/ArrayDeque;
+HPLcom/android/server/wm/TaskSnapshotPersister;->access$402(Lcom/android/server/wm/TaskSnapshotPersister;Z)Z
+HPLcom/android/server/wm/WindowAnimationSpec;->findTranslateAnimation(Landroid/view/animation/Animation;)Landroid/view/animation/TranslateAnimation;
+HPLcom/android/server/wm/WindowAnimationSpec;->writeToProtoInner(Landroid/util/proto/ProtoOutputStream;)V
+HPLcom/android/server/wm/WindowContainer;->access$100(Lcom/android/server/wm/WindowContainer;)Landroid/util/Pools$SynchronizedPool;
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java
index 06d9395..7828050 100644
--- a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsPerUserService.java
@@ -22,6 +22,7 @@
 import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.app.contentsuggestions.ClassificationsRequest;
+import android.app.contentsuggestions.ContentSuggestionsManager;
 import android.app.contentsuggestions.IClassificationsCallback;
 import android.app.contentsuggestions.ISelectionsCallback;
 import android.app.contentsuggestions.SelectionsRequest;
@@ -97,15 +98,19 @@
     void provideContextImageLocked(int taskId, @NonNull Bundle imageContextRequestExtras) {
         RemoteContentSuggestionsService service = ensureRemoteServiceLocked();
         if (service != null) {
-            ActivityManager.TaskSnapshot snapshot =
-                    mActivityTaskManagerInternal.getTaskSnapshotNoRestore(taskId, false);
             GraphicBuffer snapshotBuffer = null;
             int colorSpaceId = 0;
-            if (snapshot != null) {
-                snapshotBuffer = snapshot.getSnapshot();
-                ColorSpace colorSpace = snapshot.getColorSpace();
-                if (colorSpace != null) {
-                    colorSpaceId = colorSpace.getId();
+
+            // Skip taking TaskSnapshot when bitmap is provided.
+            if (!imageContextRequestExtras.containsKey(ContentSuggestionsManager.EXTRA_BITMAP)) {
+                ActivityManager.TaskSnapshot snapshot =
+                        mActivityTaskManagerInternal.getTaskSnapshotNoRestore(taskId, false);
+                if (snapshot != null) {
+                    snapshotBuffer = snapshot.getSnapshot();
+                    ColorSpace colorSpace = snapshot.getColorSpace();
+                    if (colorSpace != null) {
+                        colorSpaceId = colorSpace.getId();
+                    }
                 }
             }
 
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 3067beb..770de09 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -80,6 +80,7 @@
         ":vold_aidl",
         ":gsiservice_aidl",
         ":platform-compat-config",
+        ":tethering-servicescore-srcs",
         "java/com/android/server/EventLogTags.logtags",
         "java/com/android/server/am/EventLogTags.logtags",
         "java/com/android/server/policy/EventLogTags.logtags",
@@ -114,7 +115,6 @@
         "android.hardware.contexthub-V1.0-java",
         "android.hidl.manager-V1.2-java",
         "dnsresolver_aidl_interface-V2-java",
-        "netd_aidl_interface-java",
         "netd_event_listener_interface-java",
     ],
 }
@@ -155,3 +155,11 @@
     name: "protolog.conf.json.gz",
     src: ":services.core.json.gz",
 }
+
+// TODO: this should be removed after tethering migration done.
+filegroup {
+    name: "servicescore-tethering-src",
+    srcs: [
+        "java/com/android/server/connectivity/MockableSystemProperties.java",
+    ],
+}
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
similarity index 91%
rename from core/java/android/app/usage/UsageStatsManagerInternal.java
rename to services/core/java/android/app/usage/UsageStatsManagerInternal.java
index 024afe2..6641b5b 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -23,6 +23,8 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 
+import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
+
 import java.util.List;
 import java.util.Set;
 
@@ -153,35 +155,6 @@
      */
     public abstract int[] getIdleUidsForUser(@UserIdInt int userId);
 
-    /**
-     * Sets up a listener for changes to packages being accessed.
-     * @param listener A listener within the system process.
-     */
-    public abstract void addAppIdleStateChangeListener(
-            AppIdleStateChangeListener listener);
-
-    /**
-     * Removes a listener that was previously added for package usage state changes.
-     * @param listener The listener within the system process to remove.
-     */
-    public abstract void removeAppIdleStateChangeListener(
-            AppIdleStateChangeListener listener);
-
-    public static abstract class AppIdleStateChangeListener {
-
-        /** Callback to inform listeners that the idle state has changed to a new bucket. */
-        public abstract void onAppIdleStateChanged(String packageName, @UserIdInt int userId,
-                boolean idle, int bucket, int reason);
-
-        /**
-         * Optional callback to inform the listener that the app has transitioned into
-         * an active state due to user interaction.
-         */
-        public void onUserInteractionStarted(String packageName, @UserIdInt int userId) {
-            // No-op by default
-        }
-    }
-
     /**  Backup/Restore API */
     public abstract byte[] getBackupPayload(@UserIdInt int userId, String key);
 
diff --git a/core/java/android/os/BatteryStatsInternal.java b/services/core/java/android/os/BatteryStatsInternal.java
similarity index 100%
rename from core/java/android/os/BatteryStatsInternal.java
rename to services/core/java/android/os/BatteryStatsInternal.java
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index b41e95f..e757b4e 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -99,6 +99,8 @@
 import com.android.internal.util.LocalLog;
 import com.android.internal.util.StatLogger;
 import com.android.server.AppStateTracker.Listener;
+import com.android.server.usage.AppStandbyInternal;
+import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
 
 import java.io.ByteArrayOutputStream;
 import java.io.FileDescriptor;
@@ -152,7 +154,7 @@
     static final int TICK_HISTORY_DEPTH = 10;
     static final long MILLIS_IN_DAY = 24 * 60 * 60 * 1000;
 
-    // Indices into the APP_STANDBY_MIN_DELAYS and KEYS_APP_STANDBY_DELAY arrays
+    // Indices into the KEYS_APP_STANDBY_QUOTAS array.
     static final int ACTIVE_INDEX = 0;
     static final int WORKING_INDEX = 1;
     static final int FREQUENT_INDEX = 2;
@@ -399,8 +401,6 @@
         static final String KEY_LISTENER_TIMEOUT = "listener_timeout";
         @VisibleForTesting
         static final String KEY_MAX_ALARMS_PER_UID = "max_alarms_per_uid";
-        @VisibleForTesting
-        static final String KEY_APP_STANDBY_QUOTAS_ENABLED = "app_standby_quotas_enabled";
         private static final String KEY_APP_STANDBY_WINDOW = "app_standby_window";
         @VisibleForTesting
         final String[] KEYS_APP_STANDBY_QUOTAS = {
@@ -411,15 +411,6 @@
                 "standby_never_quota",
         };
 
-        // Keys for specifying throttling delay based on app standby bucketing
-        private final String[] KEYS_APP_STANDBY_DELAY = {
-                "standby_active_delay",
-                "standby_working_delay",
-                "standby_frequent_delay",
-                "standby_rare_delay",
-                "standby_never_delay",
-        };
-
         private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
         private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
         private static final long DEFAULT_MAX_INTERVAL = 365 * DateUtils.DAY_IN_MILLIS;
@@ -428,7 +419,6 @@
         private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000;
         private static final long DEFAULT_LISTENER_TIMEOUT = 5 * 1000;
         private static final int DEFAULT_MAX_ALARMS_PER_UID = 500;
-        private static final boolean DEFAULT_APP_STANDBY_QUOTAS_ENABLED = true;
         private static final long DEFAULT_APP_STANDBY_WINDOW = 60 * 60 * 1000;  // 1 hr
         /**
          * Max number of times an app can receive alarms in {@link #APP_STANDBY_WINDOW}
@@ -440,13 +430,6 @@
                 1,      // Rare
                 0       // Never
         };
-        private final long[] DEFAULT_APP_STANDBY_DELAYS = {
-                0,                       // Active
-                6 * 60_000,              // Working
-                30 * 60_000,             // Frequent
-                2 * 60 * 60_000,         // Rare
-                10 * 24 * 60 * 60_000    // Never
-        };
 
         // Minimum futurity of a new alarm
         public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;
@@ -471,10 +454,7 @@
         public long LISTENER_TIMEOUT = DEFAULT_LISTENER_TIMEOUT;
         public int MAX_ALARMS_PER_UID = DEFAULT_MAX_ALARMS_PER_UID;
 
-        public boolean APP_STANDBY_QUOTAS_ENABLED = DEFAULT_APP_STANDBY_QUOTAS_ENABLED;
-
         public long APP_STANDBY_WINDOW = DEFAULT_APP_STANDBY_WINDOW;
-        public long[] APP_STANDBY_MIN_DELAYS = new long[DEFAULT_APP_STANDBY_DELAYS.length];
         public int[] APP_STANDBY_QUOTAS = new int[DEFAULT_APP_STANDBY_QUOTAS.length];
 
         private ContentResolver mResolver;
@@ -530,16 +510,6 @@
                         DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION);
                 LISTENER_TIMEOUT = mParser.getLong(KEY_LISTENER_TIMEOUT,
                         DEFAULT_LISTENER_TIMEOUT);
-                APP_STANDBY_MIN_DELAYS[ACTIVE_INDEX] = mParser.getDurationMillis(
-                        KEYS_APP_STANDBY_DELAY[ACTIVE_INDEX],
-                        DEFAULT_APP_STANDBY_DELAYS[ACTIVE_INDEX]);
-                for (int i = WORKING_INDEX; i < KEYS_APP_STANDBY_DELAY.length; i++) {
-                    APP_STANDBY_MIN_DELAYS[i] = mParser.getDurationMillis(KEYS_APP_STANDBY_DELAY[i],
-                            Math.max(APP_STANDBY_MIN_DELAYS[i - 1], DEFAULT_APP_STANDBY_DELAYS[i]));
-                }
-
-                APP_STANDBY_QUOTAS_ENABLED = mParser.getBoolean(KEY_APP_STANDBY_QUOTAS_ENABLED,
-                        DEFAULT_APP_STANDBY_QUOTAS_ENABLED);
 
                 APP_STANDBY_WINDOW = mParser.getLong(KEY_APP_STANDBY_WINDOW,
                         DEFAULT_APP_STANDBY_WINDOW);
@@ -612,15 +582,6 @@
             pw.print(KEY_MAX_ALARMS_PER_UID); pw.print("=");
             pw.println(MAX_ALARMS_PER_UID);
 
-            for (int i = 0; i < KEYS_APP_STANDBY_DELAY.length; i++) {
-                pw.print(KEYS_APP_STANDBY_DELAY[i]); pw.print("=");
-                TimeUtils.formatDuration(APP_STANDBY_MIN_DELAYS[i], pw);
-                pw.println();
-            }
-
-            pw.print(KEY_APP_STANDBY_QUOTAS_ENABLED); pw.print("=");
-            pw.println(APP_STANDBY_QUOTAS_ENABLED);
-
             pw.print(KEY_APP_STANDBY_WINDOW); pw.print("=");
             TimeUtils.formatDuration(APP_STANDBY_WINDOW, pw);
             pw.println();
@@ -1599,7 +1560,9 @@
                         LocalServices.getService(DeviceIdleInternal.class);
                 mUsageStatsManagerInternal =
                         LocalServices.getService(UsageStatsManagerInternal.class);
-                mUsageStatsManagerInternal.addAppIdleStateChangeListener(new AppStandbyTracker());
+                AppStandbyInternal appStandbyInternal =
+                        LocalServices.getService(AppStandbyInternal.class);
+                appStandbyInternal.addListener(new AppStandbyTracker());
 
                 mAppStateTracker = LocalServices.getService(AppStateTracker.class);
                 mAppStateTracker.addListener(mForceAppStandbyListener);
@@ -1822,27 +1785,6 @@
     }
 
     /**
-     * Return the minimum time that should elapse before an app in the specified bucket
-     * can receive alarms again
-     */
-    @VisibleForTesting
-    long getMinDelayForBucketLocked(int bucket) {
-        // UsageStats bucket values are treated as floors of their behavioral range.
-        // In other words, a bucket value between WORKING and ACTIVE is treated as
-        // WORKING, not as ACTIVE.  The ACTIVE and NEVER bucket apply only at specific
-        // values.
-        final int index;
-
-        if (bucket == UsageStatsManager.STANDBY_BUCKET_NEVER) index = NEVER_INDEX;
-        else if (bucket > UsageStatsManager.STANDBY_BUCKET_FREQUENT) index = RARE_INDEX;
-        else if (bucket > UsageStatsManager.STANDBY_BUCKET_WORKING_SET) index = FREQUENT_INDEX;
-        else if (bucket > UsageStatsManager.STANDBY_BUCKET_ACTIVE) index = WORKING_INDEX;
-        else index = ACTIVE_INDEX;
-
-        return mConstants.APP_STANDBY_MIN_DELAYS[index];
-    }
-
-    /**
      * Adjusts the alarm delivery time based on the current app standby bucket.
      * @param alarm The alarm to adjust
      * @return true if the alarm delivery time was updated.
@@ -1868,50 +1810,34 @@
         final int standbyBucket = mUsageStatsManagerInternal.getAppStandbyBucket(
                 sourcePackage, sourceUserId, mInjector.getElapsedRealtime());
 
-        if (mConstants.APP_STANDBY_QUOTAS_ENABLED) {
-            // Quota deferring implementation:
-            final int wakeupsInWindow = mAppWakeupHistory.getTotalWakeupsInWindow(sourcePackage,
-                    sourceUserId);
-            final int quotaForBucket = getQuotaForBucketLocked(standbyBucket);
-            boolean deferred = false;
-            if (wakeupsInWindow >= quotaForBucket) {
-                final long minElapsed;
-                if (quotaForBucket <= 0) {
-                    // Just keep deferring for a day till the quota changes
-                    minElapsed = mInjector.getElapsedRealtime() + MILLIS_IN_DAY;
-                } else {
-                    // Suppose the quota for window was q, and the qth last delivery time for this
-                    // package was t(q) then the next delivery must be after t(q) + <window_size>
-                    final long t = mAppWakeupHistory.getLastWakeupForPackage(sourcePackage,
-                            sourceUserId, quotaForBucket);
-                    minElapsed = t + 1 + mConstants.APP_STANDBY_WINDOW;
-                }
-                if (alarm.expectedWhenElapsed < minElapsed) {
-                    alarm.whenElapsed = alarm.maxWhenElapsed = minElapsed;
-                    deferred = true;
-                }
+        // Quota deferring implementation:
+        final int wakeupsInWindow = mAppWakeupHistory.getTotalWakeupsInWindow(sourcePackage,
+                sourceUserId);
+        final int quotaForBucket = getQuotaForBucketLocked(standbyBucket);
+        boolean deferred = false;
+        if (wakeupsInWindow >= quotaForBucket) {
+            final long minElapsed;
+            if (quotaForBucket <= 0) {
+                // Just keep deferring for a day till the quota changes
+                minElapsed = mInjector.getElapsedRealtime() + MILLIS_IN_DAY;
+            } else {
+                // Suppose the quota for window was q, and the qth last delivery time for this
+                // package was t(q) then the next delivery must be after t(q) + <window_size>
+                final long t = mAppWakeupHistory.getLastWakeupForPackage(sourcePackage,
+                        sourceUserId, quotaForBucket);
+                minElapsed = t + 1 + mConstants.APP_STANDBY_WINDOW;
             }
-            if (!deferred) {
-                // Restore original requirements in case they were changed earlier.
-                alarm.whenElapsed = alarm.expectedWhenElapsed;
-                alarm.maxWhenElapsed = alarm.expectedMaxWhenElapsed;
-            }
-        } else {
-            // Minimum delay deferring implementation:
-            final long lastElapsed = mAppWakeupHistory.getLastWakeupForPackage(sourcePackage,
-                    sourceUserId, 1);
-            if (lastElapsed > 0) {
-                final long minElapsed = lastElapsed + getMinDelayForBucketLocked(standbyBucket);
-                if (alarm.expectedWhenElapsed < minElapsed) {
-                    alarm.whenElapsed = alarm.maxWhenElapsed = minElapsed;
-                } else {
-                    // app is now eligible to run alarms at the originally requested window.
-                    // Restore original requirements in case they were changed earlier.
-                    alarm.whenElapsed = alarm.expectedWhenElapsed;
-                    alarm.maxWhenElapsed = alarm.expectedMaxWhenElapsed;
-                }
+            if (alarm.expectedWhenElapsed < minElapsed) {
+                alarm.whenElapsed = alarm.maxWhenElapsed = minElapsed;
+                deferred = true;
             }
         }
+        if (!deferred) {
+            // Restore original requirements in case they were changed earlier.
+            alarm.whenElapsed = alarm.expectedWhenElapsed;
+            alarm.maxWhenElapsed = alarm.expectedMaxWhenElapsed;
+        }
+
         return (oldWhenElapsed != alarm.whenElapsed || oldMaxWhenElapsed != alarm.maxWhenElapsed);
     }
 
@@ -4442,7 +4368,8 @@
     }
 
     final class UidObserver extends IUidObserver.Stub {
-        @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
+        @Override public void onUidStateChanged(int uid, int procState, long procStateSeq,
+            int capability) {
         }
 
         @Override public void onUidGone(int uid, boolean disabled) {
@@ -4468,7 +4395,7 @@
      * Tracking of app assignments to standby buckets
      */
     private final class AppStandbyTracker extends
-            UsageStatsManagerInternal.AppIdleStateChangeListener {
+            AppIdleStateChangeListener {
         @Override
         public void onAppIdleStateChanged(final String packageName, final @UserIdInt int userId,
                 boolean idle, int bucket, int reason) {
diff --git a/services/core/java/com/android/server/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java
index da760b6..486cd5f 100644
--- a/services/core/java/com/android/server/AppStateTracker.java
+++ b/services/core/java/com/android/server/AppStateTracker.java
@@ -24,7 +24,6 @@
 import android.app.IUidObserver;
 import android.app.usage.UsageStatsManager;
 import android.app.usage.UsageStatsManagerInternal;
-import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -58,6 +57,8 @@
 import com.android.internal.util.StatLogger;
 import com.android.server.AppStateTrackerProto.ExemptedPackage;
 import com.android.server.AppStateTrackerProto.RunAnyInBackgroundRestrictedPackages;
+import com.android.server.usage.AppStandbyInternal;
+import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
 
 import java.io.PrintWriter;
 import java.util.Arrays;
@@ -89,7 +90,7 @@
     IAppOpsService mAppOpsService;
     PowerManagerInternal mPowerManagerInternal;
     StandbyTracker mStandbyTracker;
-    UsageStatsManagerInternal mUsageStatsManagerInternal;
+    AppStandbyInternal mAppStandbyInternal;
 
     private final MyHandler mHandler;
 
@@ -420,8 +421,7 @@
             mAppOpsManager = Preconditions.checkNotNull(injectAppOpsManager());
             mAppOpsService = Preconditions.checkNotNull(injectIAppOpsService());
             mPowerManagerInternal = Preconditions.checkNotNull(injectPowerManagerInternal());
-            mUsageStatsManagerInternal = Preconditions.checkNotNull(
-                    injectUsageStatsManagerInternal());
+            mAppStandbyInternal = Preconditions.checkNotNull(injectAppStandbyInternal());
 
             mFlagsObserver = new FeatureFlagsObserver();
             mFlagsObserver.register();
@@ -429,7 +429,7 @@
             mForceAllAppStandbyForSmallBattery =
                     mFlagsObserver.isForcedAppStandbyForSmallBatteryEnabled();
             mStandbyTracker = new StandbyTracker();
-            mUsageStatsManagerInternal.addAppIdleStateChangeListener(mStandbyTracker);
+            mAppStandbyInternal.addListener(mStandbyTracker);
 
             try {
                 mIActivityManager.registerUidObserver(new UidObserver(),
@@ -494,8 +494,8 @@
     }
 
     @VisibleForTesting
-    UsageStatsManagerInternal injectUsageStatsManagerInternal() {
-        return LocalServices.getService(UsageStatsManagerInternal.class);
+    AppStandbyInternal injectAppStandbyInternal() {
+        return LocalServices.getService(AppStandbyInternal.class);
     }
 
     @VisibleForTesting
@@ -632,7 +632,7 @@
 
     private final class UidObserver extends IUidObserver.Stub {
         @Override
-        public void onUidStateChanged(int uid, int procState, long procStateSeq) {
+        public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) {
             mHandler.onUidStateChanged(uid, procState);
         }
 
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 0bb72cb..ce0e9e7 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -26,6 +26,7 @@
 import static android.net.ConnectivityManager.TYPE_VPN;
 import static android.net.ConnectivityManager.getNetworkTypeName;
 import static android.net.ConnectivityManager.isNetworkTypeValid;
+import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
@@ -528,6 +529,15 @@
     private static final int EVENT_SET_ACCEPT_PARTIAL_CONNECTIVITY = 45;
 
     /**
+     * Event for NetworkMonitor to inform ConnectivityService that the probe status has changed.
+     * Both of the arguments are bitmasks, and the value of bits come from
+     * INetworkMonitor.NETWORK_VALIDATION_PROBE_*.
+     * arg1 = A bitmask to describe which probes are completed.
+     * arg2 = A bitmask to describe which probes are successful.
+     */
+    public static final int EVENT_PROBE_STATUS_CHANGED = 46;
+
+    /**
      * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
      * should be shown.
      */
@@ -2663,6 +2673,41 @@
             switch (msg.what) {
                 default:
                     return false;
+                case EVENT_PROBE_STATUS_CHANGED: {
+                    final Integer netId = (Integer) msg.obj;
+                    final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId);
+                    if (nai == null) {
+                        break;
+                    }
+                    final boolean probePrivateDnsCompleted =
+                            ((msg.arg1 & NETWORK_VALIDATION_PROBE_PRIVDNS) != 0);
+                    final boolean privateDnsBroken =
+                            ((msg.arg2 & NETWORK_VALIDATION_PROBE_PRIVDNS) == 0);
+                    if (probePrivateDnsCompleted) {
+                        if (nai.networkCapabilities.isPrivateDnsBroken() != privateDnsBroken) {
+                            nai.networkCapabilities.setPrivateDnsBroken(privateDnsBroken);
+                            final int oldScore = nai.getCurrentScore();
+                            updateCapabilities(oldScore, nai, nai.networkCapabilities);
+                        }
+                        // Only show the notification when the private DNS is broken and the
+                        // PRIVATE_DNS_BROKEN notification hasn't shown since last valid.
+                        if (privateDnsBroken && !nai.networkMisc.hasShownBroken) {
+                            showNetworkNotification(nai, NotificationType.PRIVATE_DNS_BROKEN);
+                        }
+                        nai.networkMisc.hasShownBroken = privateDnsBroken;
+                    } else if (nai.networkCapabilities.isPrivateDnsBroken()) {
+                        // If probePrivateDnsCompleted is false but nai.networkCapabilities says
+                        // private DNS is broken, it means this network is being reevaluated.
+                        // Either probing private DNS is not necessary any more or it hasn't been
+                        // done yet. In either case, the networkCapabilities should be updated to
+                        // reflect the new status.
+                        nai.networkCapabilities.setPrivateDnsBroken(false);
+                        final int oldScore = nai.getCurrentScore();
+                        updateCapabilities(oldScore, nai, nai.networkCapabilities);
+                        nai.networkMisc.hasShownBroken = false;
+                    }
+                    break;
+                }
                 case EVENT_NETWORK_TESTED: {
                     final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
                     if (nai == null) break;
@@ -2705,14 +2750,20 @@
                         if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai);
                         if (valid) {
                             handleFreshlyValidatedNetwork(nai);
-                            // Clear NO_INTERNET, PARTIAL_CONNECTIVITY and LOST_INTERNET
-                            // notifications if network becomes valid.
+                            // Clear NO_INTERNET, PRIVATE_DNS_BROKEN, PARTIAL_CONNECTIVITY and
+                            // LOST_INTERNET notifications if network becomes valid.
                             mNotifier.clearNotification(nai.network.netId,
                                     NotificationType.NO_INTERNET);
                             mNotifier.clearNotification(nai.network.netId,
                                     NotificationType.LOST_INTERNET);
                             mNotifier.clearNotification(nai.network.netId,
                                     NotificationType.PARTIAL_CONNECTIVITY);
+                            mNotifier.clearNotification(nai.network.netId,
+                                    NotificationType.PRIVATE_DNS_BROKEN);
+                            // If network becomes valid, the hasShownBroken should be reset for
+                            // that network so that the notification will be fired when the private
+                            // DNS is broken again.
+                            nai.networkMisc.hasShownBroken = false;
                         }
                     } else if (partialConnectivityChanged) {
                         updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
@@ -2863,6 +2914,13 @@
         }
 
         @Override
+        public void notifyProbeStatusChanged(int probesCompleted, int probesSucceeded) {
+            mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
+                    EVENT_PROBE_STATUS_CHANGED,
+                    probesCompleted, probesSucceeded, new Integer(mNetId)));
+        }
+
+        @Override
         public void showProvisioningNotification(String action, String packageName) {
             final Intent intent = new Intent(action);
             intent.setPackage(packageName);
@@ -3679,6 +3737,11 @@
                 // High priority because it is only displayed for explicitly selected networks.
                 highPriority = true;
                 break;
+            case PRIVATE_DNS_BROKEN:
+                action = Settings.ACTION_WIRELESS_SETTINGS;
+                // High priority because we should let user know why there is no internet.
+                highPriority = true;
+                break;
             case LOST_INTERNET:
                 action = ConnectivityManager.ACTION_PROMPT_LOST_VALIDATION;
                 // High priority because it could help the user avoid unexpected data usage.
@@ -3696,7 +3759,7 @@
         }
 
         Intent intent = new Intent(action);
-        if (type != NotificationType.LOGGED_IN) {
+        if (type != NotificationType.LOGGED_IN && type != NotificationType.PRIVATE_DNS_BROKEN) {
             intent.setData(Uri.fromParts("netId", Integer.toString(nai.network.netId), null));
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             intent.setClassName("com.android.settings",
@@ -5162,6 +5225,13 @@
         ns.assertValidFromUid(Binder.getCallingUid());
     }
 
+    private void ensureValid(NetworkCapabilities nc) {
+        ensureValidNetworkSpecifier(nc);
+        if (nc.isPrivateDnsBroken()) {
+            throw new IllegalArgumentException("Can't request broken private DNS");
+        }
+    }
+
     @Override
     public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
             Messenger messenger, int timeoutMs, IBinder binder, int legacyType) {
@@ -5195,7 +5265,7 @@
         if (timeoutMs < 0) {
             throw new IllegalArgumentException("Bad timeout specified");
         }
-        ensureValidNetworkSpecifier(networkCapabilities);
+        ensureValid(networkCapabilities);
 
         NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
                 nextNetworkRequestId(), type);
@@ -5337,7 +5407,7 @@
         // There is no need to do this for requests because an app without CHANGE_NETWORK_STATE
         // can't request networks.
         restrictBackgroundRequestForCaller(nc);
-        ensureValidNetworkSpecifier(nc);
+        ensureValid(nc);
 
         NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
                 NetworkRequest.Type.LISTEN);
@@ -5355,7 +5425,7 @@
         if (!hasWifiNetworkListenPermission(networkCapabilities)) {
             enforceAccessPermission();
         }
-        ensureValidNetworkSpecifier(networkCapabilities);
+        ensureValid(networkCapabilities);
         ensureSufficientPermissionsForRequest(networkCapabilities,
                 Binder.getCallingPid(), Binder.getCallingUid());
 
@@ -5841,6 +5911,7 @@
         } else {
             newNc.removeCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY);
         }
+        newNc.setPrivateDnsBroken(nai.networkCapabilities.isPrivateDnsBroken());
 
         return newNc;
     }
diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index aeb3e7f..028d412 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.net.Uri;
@@ -40,11 +41,13 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.service.dropbox.DropBoxManagerServiceDumpProto;
 import android.text.TextUtils;
 import android.text.format.TimeMigrationUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
@@ -65,6 +68,7 @@
 import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.zip.GZIPOutputStream;
@@ -85,6 +89,9 @@
 
     private static final boolean PROFILE_DUMP = false;
 
+    // Max number of bytes of a dropbox entry to write into protobuf.
+    private static final int PROTO_MAX_DATA_BYTES = 256 * 1024;
+
     // TODO: This implementation currently uses one file per entry, which is
     // inefficient for smallish entries -- consider using a single queue file
     // per tag (or even globally) instead.
@@ -464,6 +471,14 @@
     }
 
     private boolean checkPermission(int callingUid, String callingPackage) {
+        // If callers have this permission, then we don't need to check
+        // USAGE_STATS, because they are part of the system and have agreed to
+        // check USAGE_STATS before passing the data along.
+        if (getContext().checkCallingPermission(android.Manifest.permission.PEEK_DROPBOX_DATA)
+                == PackageManager.PERMISSION_GRANTED) {
+            return true;
+        }
+
         // Callers always need this permission
         getContext().enforceCallingOrSelfPermission(
                 android.Manifest.permission.READ_LOGS, TAG);
@@ -547,18 +562,22 @@
 
         StringBuilder out = new StringBuilder();
         boolean doPrint = false, doFile = false;
+        boolean dumpProto = false;
         ArrayList<String> searchArgs = new ArrayList<String>();
         for (int i = 0; args != null && i < args.length; i++) {
             if (args[i].equals("-p") || args[i].equals("--print")) {
                 doPrint = true;
             } else if (args[i].equals("-f") || args[i].equals("--file")) {
                 doFile = true;
+            } else if (args[i].equals("--proto")) {
+                dumpProto = true;
             } else if (args[i].equals("-h") || args[i].equals("--help")) {
                 pw.println("Dropbox (dropbox) dump options:");
                 pw.println("  [-h|--help] [-p|--print] [-f|--file] [timestamp]");
                 pw.println("    -h|--help: print this help");
                 pw.println("    -p|--print: print full contents of each entry");
                 pw.println("    -f|--file: print path of each entry's file");
+                pw.println("    --proto: dump data to proto");
                 pw.println("  [timestamp] optionally filters to only those entries.");
                 return;
             } else if (args[i].startsWith("-")) {
@@ -568,6 +587,11 @@
             }
         }
 
+        if (dumpProto) {
+            dumpProtoLocked(fd, searchArgs);
+            return;
+        }
+
         out.append("Drop box contents: ").append(mAllFiles.contents.size()).append(" entries\n");
         out.append("Max entries: ").append(mMaxFiles).append("\n");
 
@@ -581,19 +605,15 @@
             out.append("\n");
         }
 
-        int numFound = 0, numArgs = searchArgs.size();
+        int numFound = 0;
         out.append("\n");
         for (EntryFile entry : mAllFiles.contents) {
-            String date = TimeMigrationUtils.formatMillisWithFixedFormat(entry.timestampMillis);
-            boolean match = true;
-            for (int i = 0; i < numArgs && match; i++) {
-                String arg = searchArgs.get(i);
-                match = (date.contains(arg) || arg.equals(entry.tag));
-            }
-            if (!match) continue;
+            if (!matchEntry(entry, searchArgs)) continue;
 
             numFound++;
             if (doPrint) out.append("========================================\n");
+
+            String date = TimeMigrationUtils.formatMillisWithFixedFormat(entry.timestampMillis);
             out.append(date).append(" ").append(entry.tag == null ? "(no tag)" : entry.tag);
 
             final File file = entry.getFile(mDropBoxDir);
@@ -679,6 +699,55 @@
         if (PROFILE_DUMP) Debug.stopMethodTracing();
     }
 
+    private boolean matchEntry(EntryFile entry, ArrayList<String> searchArgs) {
+        String date = TimeMigrationUtils.formatMillisWithFixedFormat(entry.timestampMillis);
+        boolean match = true;
+        int numArgs = searchArgs.size();
+        for (int i = 0; i < numArgs && match; i++) {
+            String arg = searchArgs.get(i);
+            match = (date.contains(arg) || arg.equals(entry.tag));
+        }
+        return match;
+    }
+
+    private void dumpProtoLocked(FileDescriptor fd, ArrayList<String> searchArgs) {
+        final ProtoOutputStream proto = new ProtoOutputStream(fd);
+
+        for (EntryFile entry : mAllFiles.contents) {
+            if (!matchEntry(entry, searchArgs)) continue;
+
+            final File file = entry.getFile(mDropBoxDir);
+            if ((file == null) || ((entry.flags & DropBoxManager.IS_EMPTY) != 0)) {
+                continue;
+            }
+
+            final long bToken = proto.start(DropBoxManagerServiceDumpProto.ENTRIES);
+            proto.write(DropBoxManagerServiceDumpProto.Entry.TIME_MS, entry.timestampMillis);
+            try (
+                DropBoxManager.Entry dbe = new DropBoxManager.Entry(
+                        entry.tag, entry.timestampMillis, file, entry.flags);
+                InputStream is = dbe.getInputStream();
+            ) {
+                if (is != null) {
+                    byte[] buf = new byte[PROTO_MAX_DATA_BYTES];
+                    int readBytes = 0;
+                    int n = 0;
+                    while (n >= 0 && (readBytes += n) < PROTO_MAX_DATA_BYTES) {
+                        n = is.read(buf, readBytes, PROTO_MAX_DATA_BYTES - readBytes);
+                    }
+                    proto.write(DropBoxManagerServiceDumpProto.Entry.DATA,
+                            Arrays.copyOf(buf, readBytes));
+                }
+            } catch (IOException e) {
+                Slog.e(TAG, "Can't read: " + file, e);
+            }
+
+            proto.end(bToken);
+        }
+
+        proto.flush();
+    }
+
     ///////////////////////////////////////////////////////////////////////////
 
     /** Chronologically sorted list of {@link EntryFile} */
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 18009e1..190e6cf 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -115,7 +115,8 @@
     }
 
     @Override
-    public boolean startInstallation(long systemSize, long userdataSize) throws RemoteException {
+    public boolean startInstallation(String name, long size, boolean readOnly)
+            throws RemoteException {
         // priority from high to low: sysprop -> sdcard -> /data
         String path = SystemProperties.get("os.aot.path");
         if (path.isEmpty()) {
@@ -137,11 +138,18 @@
             }
             Slog.i(TAG, "startInstallation -> " + path);
         }
+        IGsiService service = getGsiService();
         GsiInstallParams installParams = new GsiInstallParams();
         installParams.installDir = path;
-        installParams.gsiSize = systemSize;
-        installParams.userdataSize = userdataSize;
-        return getGsiService().beginGsiInstall(installParams) == 0;
+        installParams.name = name;
+        installParams.size = size;
+        installParams.wipe = readOnly;
+        installParams.readOnly = readOnly;
+        if (service.beginGsiInstall(installParams) != 0) {
+            Slog.i(TAG, "Failed to install " + name);
+            return false;
+        }
+        return true;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/GnssManagerService.java b/services/core/java/com/android/server/GnssManagerService.java
index 44a8234..cbf2a62 100644
--- a/services/core/java/com/android/server/GnssManagerService.java
+++ b/services/core/java/com/android/server/GnssManagerService.java
@@ -18,6 +18,7 @@
 
 import android.Manifest;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.content.Context;
@@ -66,7 +67,7 @@
 
 /** Manages Gnss providers and related Gnss functions for LocationManagerService. */
 public class GnssManagerService {
-    private static final String TAG = "LocationManagerService";
+    private static final String TAG = "GnssManagerService";
     private static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
 
     // Providers
@@ -123,7 +124,7 @@
 
     // Can use this constructor to inject GnssLocationProvider for testing
     @VisibleForTesting
-    GnssManagerService(LocationManagerService locationManagerService,
+    public GnssManagerService(LocationManagerService locationManagerService,
             Context context,
             GnssLocationProvider gnssLocationProvider,
             LocationUsageLogger locationUsageLogger) {
@@ -300,7 +301,7 @@
      * @return true if callback is successfully added, false otherwise
      */
     public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName,
-            @NonNull String listenerIdentity) {
+            @Nullable String featureId, @NonNull String listenerIdentity) {
         mContext.enforceCallingPermission(
                 android.Manifest.permission.LOCATION_HARDWARE,
                 "Location Hardware permission not granted to access hardware batching");
@@ -319,7 +320,7 @@
 
         CallerIdentity callerIdentity =
                 new CallerIdentity(Binder.getCallingUid(), Binder.getCallingPid(), packageName,
-                        listenerIdentity);
+                        featureId, listenerIdentity);
         synchronized (mGnssBatchingLock) {
             mGnssBatchingCallback = callback;
             mGnssBatchingDeathCallback =
@@ -497,6 +498,7 @@
     private <TListener extends IInterface> boolean addGnssDataListenerLocked(
             TListener listener,
             String packageName,
+            @Nullable String featureId,
             @NonNull String listenerIdentifier,
             RemoteListenerHelper<TListener> gnssDataProvider,
             ArrayMap<IBinder,
@@ -517,7 +519,7 @@
 
         CallerIdentity callerIdentity =
                 new CallerIdentity(Binder.getCallingUid(), Binder.getCallingPid(), packageName,
-                        listenerIdentifier);
+                        featureId, listenerIdentifier);
         LinkedListener<TListener> linkedListener =
                 new LocationManagerServiceUtils.LinkedListener<>(
                         listener, listenerIdentifier, callerIdentity, binderDeathCallback);
@@ -605,11 +607,13 @@
      * @param packageName name of requesting package
      * @return true if listener is successfully registered, false otherwise
      */
-    public boolean registerGnssStatusCallback(IGnssStatusListener listener, String packageName) {
+    public boolean registerGnssStatusCallback(IGnssStatusListener listener, String packageName,
+            @Nullable String featureId) {
         synchronized (mGnssStatusListeners) {
             return addGnssDataListenerLocked(
                     listener,
                     packageName,
+                    featureId,
                     "Gnss status",
                     mGnssStatusProvider,
                     mGnssStatusListeners,
@@ -636,12 +640,13 @@
      * @return true if listener is successfully added, false otherwise
      */
     public boolean addGnssMeasurementsListener(
-            IGnssMeasurementsListener listener, String packageName,
+            IGnssMeasurementsListener listener, String packageName, @Nullable String featureId,
             @NonNull String listenerIdentifier) {
         synchronized (mGnssMeasurementsListeners) {
             return addGnssDataListenerLocked(
                     listener,
                     packageName,
+                    featureId,
                     listenerIdentifier,
                     mGnssMeasurementsProvider,
                     mGnssMeasurementsListeners,
@@ -695,11 +700,12 @@
      */
     public boolean addGnssNavigationMessageListener(
             IGnssNavigationMessageListener listener, String packageName,
-            @NonNull String listenerIdentifier) {
+            @Nullable String featureId, @NonNull String listenerIdentifier) {
         synchronized (mGnssNavigationMessageListeners) {
             return addGnssDataListenerLocked(
                     listener,
                     packageName,
+                    featureId,
                     listenerIdentifier,
                     mGnssNavigationMessageProvider,
                     mGnssNavigationMessageListeners,
@@ -713,8 +719,10 @@
      * @param listener called when navigation message is received
      */
     public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
-        removeGnssDataListener(
-                listener, mGnssNavigationMessageProvider, mGnssNavigationMessageListeners);
+        synchronized (mGnssNavigationMessageListeners) {
+            removeGnssDataListener(
+                    listener, mGnssNavigationMessageProvider, mGnssNavigationMessageListeners);
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 1d22b82..39f039a 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -128,6 +128,32 @@
  * updates and alerts.
  */
 public class LocationManagerService extends ILocationManager.Stub {
+
+    /**
+     * Controls lifecycle of LocationManagerService.
+     */
+    public static class Lifecycle extends SystemService {
+
+        private LocationManagerService mService;
+
+        public Lifecycle(Context context) {
+            super(context);
+            mService = new LocationManagerService(context);
+        }
+
+        @Override
+        public void onStart() {
+            publishBinderService(Context.LOCATION_SERVICE, mService);
+        }
+
+        @Override
+        public void onBootPhase(int phase) {
+            if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+                mService.systemRunning();
+            }
+        }
+    }
+
     private static final String TAG = "LocationManagerService";
     public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -234,8 +260,7 @@
     @GuardedBy("mLock")
     private final LocationUsageLogger mLocationUsageLogger;
 
-    public LocationManagerService(Context context) {
-        super();
+    private LocationManagerService(Context context) {
         mContext = context;
         mHandler = FgThread.getHandler();
         mLocationUsageLogger = new LocationUsageLogger();
@@ -254,7 +279,7 @@
         // most startup is deferred until systemRunning()
     }
 
-    public void systemRunning() {
+    private void systemRunning() {
         synchronized (mLock) {
             initializeLocked();
         }
@@ -1000,6 +1025,12 @@
 
         @Override
         public void onReportLocation(Location location) {
+            // likelihood of a 0,0 bug is far greater than this being a valid location
+            if (!isMock() && location.getLatitude() == 0 && location.getLongitude() == 0) {
+                Slog.w(TAG, "blocking 0,0 location from " + mName + " provider");
+                return;
+            }
+
             synchronized (mLock) {
                 handleLocationChangedLocked(location, this);
             }
@@ -1227,9 +1258,9 @@
         PowerManager.WakeLock mWakeLock;
 
         private Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
-                String packageName, WorkSource workSource, boolean hideFromAppOps,
-                @NonNull String listenerIdentifier) {
-            super(new CallerIdentity(uid, pid, packageName, listenerIdentifier),
+                String packageName, @Nullable String featureId, WorkSource workSource,
+                boolean hideFromAppOps, @NonNull String listenerIdentifier) {
+            super(new CallerIdentity(uid, pid, packageName, featureId, listenerIdentifier),
                     "LocationListener");
             mListener = listener;
             mPendingIntent = intent;
@@ -1354,7 +1385,8 @@
             if (!currentlyMonitoring) {
                 if (allowMonitoring) {
                     return mAppOps.startOpNoThrow(op, mCallerIdentity.mUid,
-                            mCallerIdentity.mPackageName) == AppOpsManager.MODE_ALLOWED;
+                            mCallerIdentity.mPackageName, false, mCallerIdentity.mFeatureId, null)
+                            == AppOpsManager.MODE_ALLOWED;
                 }
             } else {
                 if (!allowMonitoring
@@ -1446,6 +1478,16 @@
             return true;
         }
 
+        public void callRemovedLocked() {
+            if (mListener != null) {
+                try {
+                    mListener.onRemoved();
+                } catch (RemoteException e) {
+                    // doesn't matter
+                }
+            }
+        }
+
         @Override
         public void binderDied() {
             if (D) Log.d(TAG, "Remote " + mListenerName + " died.");
@@ -1539,11 +1581,11 @@
 
     @Override
     public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName,
-            String listenerIdentifier) {
+            String featureId, String listenerIdentifier) {
         Preconditions.checkNotNull(listenerIdentifier);
 
         return mGnssManagerService == null ? false : mGnssManagerService.addGnssBatchingCallback(
-                callback, packageName, listenerIdentifier);
+                callback, packageName, featureId, listenerIdentifier);
     }
 
     @Override
@@ -1706,10 +1748,10 @@
     }
 
     private boolean reportLocationAccessNoThrow(int pid, int uid, String packageName,
-            int allowedResolutionLevel, @Nullable String message) {
+            @Nullable String featureId, int allowedResolutionLevel, @Nullable String message) {
         int op = resolutionLevelToOp(allowedResolutionLevel);
         if (op >= 0) {
-            if (mAppOps.noteOpNoThrow(op, uid, packageName, null, message)
+            if (mAppOps.noteOpNoThrow(op, uid, packageName, featureId, message)
                     != AppOpsManager.MODE_ALLOWED) {
                 return false;
             }
@@ -2044,6 +2086,18 @@
          * Note: must be constructed with lock held.
          */
         private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
+            // translate expireIn value into expireAt
+            long elapsedRealtime = SystemClock.elapsedRealtime();
+            long expireAt;
+            // Check for > Long.MAX_VALUE overflow (elapsedRealtime > 0):
+            if (request.getExpireIn() > Long.MAX_VALUE - elapsedRealtime) {
+                expireAt = Long.MAX_VALUE;
+            } else {
+                expireAt = Math.max(request.getExpireIn() + elapsedRealtime, 0);
+            }
+            request.setExpireAt(Math.min(request.getExpireAt(), expireAt));
+            request.setExpireIn(Long.MAX_VALUE);
+
             mProvider = provider;
             mRealRequest = request;
             mRequest = request;
@@ -2143,12 +2197,12 @@
 
     @GuardedBy("mLock")
     private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
-            String packageName, WorkSource workSource, boolean hideFromAppOps,
-            @NonNull String listenerIdentifier) {
+            String packageName, @Nullable String featureId, WorkSource workSource,
+            boolean hideFromAppOps, @NonNull String listenerIdentifier) {
         IBinder binder = listener.asBinder();
         Receiver receiver = mReceivers.get(binder);
         if (receiver == null) {
-            receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
+            receiver = new Receiver(listener, null, pid, uid, packageName, featureId, workSource,
                     hideFromAppOps, listenerIdentifier);
             if (!receiver.linkToListenerDeathNotificationLocked(
                     receiver.getListener().asBinder())) {
@@ -2161,10 +2215,11 @@
 
     @GuardedBy("mLock")
     private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
-            WorkSource workSource, boolean hideFromAppOps, @NonNull String listenerIdentifier) {
+            @Nullable String featureId, WorkSource workSource, boolean hideFromAppOps,
+            @NonNull String listenerIdentifier) {
         Receiver receiver = mReceivers.get(intent);
         if (receiver == null) {
-            receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
+            receiver = new Receiver(null, intent, pid, uid, packageName, featureId, workSource,
                     hideFromAppOps, listenerIdentifier);
             mReceivers.put(intent, receiver);
         }
@@ -2227,7 +2282,8 @@
 
     @Override
     public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
-            PendingIntent intent, String packageName, String listenerIdentifier) {
+            PendingIntent intent, String packageName, String featureId,
+            String listenerIdentifier) {
         Preconditions.checkNotNull(listenerIdentifier);
 
         synchronized (mLock) {
@@ -2283,11 +2339,11 @@
 
                 Receiver receiver;
                 if (intent != null) {
-                    receiver = getReceiverLocked(intent, pid, uid, packageName, workSource,
-                            hideFromAppOps, listenerIdentifier);
+                    receiver = getReceiverLocked(intent, pid, uid, packageName, featureId,
+                            workSource, hideFromAppOps, listenerIdentifier);
                 } else {
-                    receiver = getReceiverLocked(listener, pid, uid, packageName, workSource,
-                            hideFromAppOps, listenerIdentifier);
+                    receiver = getReceiverLocked(listener, pid, uid, packageName, featureId,
+                            workSource, hideFromAppOps, listenerIdentifier);
                 }
                 requestLocationUpdatesLocked(sanitizedRequest, receiver, uid, packageName);
             } finally {
@@ -2356,9 +2412,10 @@
         synchronized (mLock) {
             Receiver receiver;
             if (intent != null) {
-                receiver = getReceiverLocked(intent, pid, uid, packageName, null, false, "");
+                receiver = getReceiverLocked(intent, pid, uid, packageName, null, null, false, "");
             } else {
-                receiver = getReceiverLocked(listener, pid, uid, packageName, null, false, "");
+                receiver = getReceiverLocked(listener, pid, uid, packageName, null, null, false,
+                        "");
             }
 
             long identity = Binder.clearCallingIdentity();
@@ -2402,7 +2459,7 @@
     }
 
     @Override
-    public Location getLastLocation(LocationRequest r, String packageName) {
+    public Location getLastLocation(LocationRequest r, String packageName, String featureId) {
         synchronized (mLock) {
             LocationRequest request = r != null ? r : DEFAULT_LOCATION_REQUEST;
             int allowedResolutionLevel = getCallerAllowedResolutionLevel();
@@ -2477,8 +2534,8 @@
                 }
                 // Don't report location access if there is no last location to deliver.
                 if (lastLocation != null) {
-                    if (!reportLocationAccessNoThrow(pid, uid, packageName, allowedResolutionLevel,
-                            null)) {
+                    if (!reportLocationAccessNoThrow(pid, uid, packageName, featureId,
+                            allowedResolutionLevel, null)) {
                         if (D) {
                             Log.d(TAG, "not returning last loc for no op app: " + packageName);
                         }
@@ -2495,9 +2552,9 @@
     @Override
     public boolean getCurrentLocation(LocationRequest locationRequest,
             ICancellationSignal remoteCancellationSignal, ILocationListener listener,
-            String packageName, String listenerIdentifier) {
+            String packageName, String featureId, String listenerIdentifier) {
         // side effect of validating locationRequest and packageName
-        Location lastLocation = getLastLocation(locationRequest, packageName);
+        Location lastLocation = getLastLocation(locationRequest, packageName, featureId);
         if (lastLocation != null) {
             long locationAgeMs = TimeUnit.NANOSECONDS.toMillis(
                     SystemClock.elapsedRealtimeNanos() - lastLocation.getElapsedRealtimeNanos());
@@ -2532,7 +2589,8 @@
             }
         }
 
-        requestLocationUpdates(locationRequest, listener, null, packageName, listenerIdentifier);
+        requestLocationUpdates(locationRequest, listener, null, packageName, featureId,
+                listenerIdentifier);
         CancellationSignal cancellationSignal = CancellationSignal.fromTransport(
                 remoteCancellationSignal);
         if (cancellationSignal != null) {
@@ -2582,7 +2640,7 @@
 
     @Override
     public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
-            String packageName, String listenerIdentifier) {
+            String packageName, String featureId, String listenerIdentifier) {
         Preconditions.checkNotNull(listenerIdentifier);
 
         if (request == null) request = DEFAULT_LOCATION_REQUEST;
@@ -2630,7 +2688,7 @@
             }
 
             mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
-                    uid, packageName, listenerIdentifier);
+                    uid, packageName, featureId, listenerIdentifier);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -2666,9 +2724,10 @@
     }
 
     @Override
-    public boolean registerGnssStatusCallback(IGnssStatusListener listener, String packageName) {
+    public boolean registerGnssStatusCallback(IGnssStatusListener listener, String packageName,
+            String featureId) {
         return mGnssManagerService == null ? false : mGnssManagerService.registerGnssStatusCallback(
-                listener, packageName);
+                listener, packageName, featureId);
     }
 
     @Override
@@ -2678,12 +2737,12 @@
 
     @Override
     public boolean addGnssMeasurementsListener(IGnssMeasurementsListener listener,
-            String packageName, String listenerIdentifier) {
+            String packageName, String featureId, String listenerIdentifier) {
         Preconditions.checkNotNull(listenerIdentifier);
 
         return mGnssManagerService == null ? false
-                : mGnssManagerService.addGnssMeasurementsListener(listener, packageName,
-                        listenerIdentifier);
+                : mGnssManagerService.addGnssMeasurementsListener(listener, packageName, featureId,
+                       listenerIdentifier);
     }
 
     @Override
@@ -2711,12 +2770,12 @@
 
     @Override
     public boolean addGnssNavigationMessageListener(IGnssNavigationMessageListener listener,
-            String packageName, String listenerIdentifier) {
+            String packageName, String featureId, String listenerIdentifier) {
         Preconditions.checkNotNull(listenerIdentifier);
 
         return mGnssManagerService == null ? false
                 : mGnssManagerService.addGnssNavigationMessageListener(listener, packageName,
-                        listenerIdentifier);
+                        featureId, listenerIdentifier);
     }
 
     @Override
@@ -3022,6 +3081,7 @@
                             receiver.mCallerIdentity.mPid,
                             receiver.mCallerIdentity.mUid,
                             receiver.mCallerIdentity.mPackageName,
+                            receiver.mCallerIdentity.mFeatureId,
                             receiver.mAllowedResolutionLevel,
                             "Location sent to " + receiver.mCallerIdentity.mListenerIdentifier)) {
                         if (D) {
@@ -3041,6 +3101,8 @@
 
             // track expired records
             if (r.mRealRequest.getNumUpdates() <= 0 || r.mRealRequest.getExpireAt() < now) {
+                // notify the client it can remove this listener
+                r.mReceiver.callRemovedLocked();
                 if (deadUpdateRecords == null) {
                     deadUpdateRecords = new ArrayList<>();
                 }
diff --git a/services/core/java/com/android/server/LocationUsageLogger.java b/services/core/java/com/android/server/LocationUsageLogger.java
index 4ca74bf..a8a3cc4 100644
--- a/services/core/java/com/android/server/LocationUsageLogger.java
+++ b/services/core/java/com/android/server/LocationUsageLogger.java
@@ -30,7 +30,7 @@
 /**
  * Logger for Location API usage logging.
  */
-class LocationUsageLogger {
+public class LocationUsageLogger {
     private static final String TAG = "LocationUsageLogger";
     private static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
 
diff --git a/services/core/java/com/android/server/NetworkScorerAppManager.java b/services/core/java/com/android/server/NetworkScorerAppManager.java
index bfd4247..3bcb36f 100644
--- a/services/core/java/com/android/server/NetworkScorerAppManager.java
+++ b/services/core/java/com/android/server/NetworkScorerAppManager.java
@@ -18,10 +18,10 @@
 
 import android.Manifest.permission;
 import android.annotation.Nullable;
-import android.app.AppOpsManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.PermissionChecker;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
@@ -210,14 +210,9 @@
     }
 
     private boolean canAccessLocation(int uid, String packageName) {
-        final PackageManager pm = mContext.getPackageManager();
-        final AppOpsManager appOpsManager =
-                (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
-        return isLocationModeEnabled()
-                && pm.checkPermission(permission.ACCESS_COARSE_LOCATION, packageName)
-                == PackageManager.PERMISSION_GRANTED
-                && appOpsManager.noteOp(AppOpsManager.OP_COARSE_LOCATION, uid, packageName)
-                == AppOpsManager.MODE_ALLOWED;
+        return isLocationModeEnabled() && PermissionChecker.checkPermissionForPreflight(mContext,
+                permission.ACCESS_COARSE_LOCATION, PermissionChecker.PID_UNKNOWN, uid, packageName)
+                == PermissionChecker.PERMISSION_GRANTED;
     }
 
     private boolean isLocationModeEnabled() {
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 49ef164..d5f7956 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -333,8 +333,8 @@
                 }
 
                 @Override
-                public void onUidStateChanged(int uid, int procState, long procStateSeq)
-                        throws RemoteException {
+                public void onUidStateChanged(int uid, int procState, long procStateSeq,
+                        int capability) throws RemoteException {
                 }
 
                 @Override
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index e3dc3b7..7f51aa9 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -51,6 +51,8 @@
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * Find the best Service, and bind to it.
@@ -64,6 +66,7 @@
     public static final String EXTRA_SERVICE_VERSION = "serviceVersion";
     public static final String EXTRA_SERVICE_IS_MULTIUSER = "serviceIsMultiuser";
 
+    private static final long BLOCKING_BINDER_TIMEOUT_MS = 30 * 1000;
 
     /** Function to run on binder interface. */
     public interface BinderRunner {
@@ -402,7 +405,7 @@
                     return defaultValue;
                 }
             });
-        } catch (InterruptedException e) {
+        } catch (InterruptedException | TimeoutException e) {
             return defaultValue;
         }
     }
@@ -439,7 +442,8 @@
         }
     }
 
-    private <T> T runOnHandlerBlocking(Callable<T> c) throws InterruptedException {
+    private <T> T runOnHandlerBlocking(Callable<T> c)
+            throws InterruptedException, TimeoutException {
         if (Looper.myLooper() == mHandler.getLooper()) {
             try {
                 return c.call();
@@ -451,7 +455,12 @@
             FutureTask<T> task = new FutureTask<>(c);
             mHandler.post(task);
             try {
-                return task.get();
+                // timeout will unblock callers, in particular if the caller is a binder thread to
+                // help reduce binder contention. this will still result in blocking the handler
+                // thread which may result in ANRs, but should make problems slightly more rare.
+                // the underlying solution is simply not to use this API at all, but that would
+                // require large refactors to very legacy code.
+                return task.get(BLOCKING_BINDER_TIMEOUT_MS, TimeUnit.MILLISECONDS);
             } catch (ExecutionException e) {
                 // Function cannot throw exception, this should never happen
                 throw new IllegalStateException(e);
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index d622fb4..b8acd7a 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -174,7 +174,8 @@
     static native long vibratorGetCapabilities();
 
     private final IUidObserver mUidObserver = new IUidObserver.Stub() {
-        @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
+        @Override public void onUidStateChanged(int uid, int procState, long procStateSeq,
+                int capability) {
             mProcStatesCache.put(uid, procState);
         }
 
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 4f54e64..b5cab1f 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -3248,7 +3248,7 @@
             UserAccounts accounts = getUserAccounts(userId);
             logRecordWithUid(
                     accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
-                    userId);
+                    uid);
             new Session(accounts, response, accountType, expectActivityLaunch,
                     true /* stripAuthTokenFromResult */, null /* accountName */,
                     false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 11cfe12..d6ecdea 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -139,6 +139,7 @@
 
 import android.Manifest;
 import android.Manifest.permission;
+import android.annotation.BroadcastBehavior;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -299,10 +300,8 @@
 import android.view.WindowManager;
 import android.view.autofill.AutofillManagerInternal;
 
-import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.DumpHeapActivity;
 import com.android.internal.app.IAppOpsCallback;
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.ProcessMap;
@@ -503,6 +502,41 @@
     static final int PERSISTENT_MASK =
             ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT;
 
+    // Intent sent when remote bugreport collection has been completed
+    private static final String INTENT_REMOTE_BUGREPORT_FINISHED =
+            "com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED";
+
+    /**
+     * Broadcast sent when heap dump collection has been completed.
+     */
+    @BroadcastBehavior(includeBackground = true, protectedBroadcast = true)
+    private static final String ACTION_HEAP_DUMP_FINISHED =
+            "com.android.internal.intent.action.HEAP_DUMP_FINISHED";
+
+    /**
+     * The process we are reporting
+     */
+    private static final String EXTRA_HEAP_DUMP_PROCESS_NAME =
+            "com.android.internal.extra.heap_dump.PROCESS_NAME";
+
+    /**
+     * The size limit the process reached.
+     */
+    private static final String EXTRA_HEAP_DUMP_SIZE_BYTES =
+            "com.android.internal.extra.heap_dump.SIZE_BYTES";
+
+    /**
+     * Whether the user initiated the dump or not.
+     */
+    private static final String EXTRA_HEAP_DUMP_IS_USER_INITIATED =
+            "com.android.internal.extra.heap_dump.IS_USER_INITIATED";
+
+    /**
+     * Optional name of package to directly launch.
+     */
+    private static final String EXTRA_HEAP_DUMP_REPORT_PACKAGE =
+            "com.android.internal.extra.heap_dump.REPORT_PACKAGE";
+
     // If set, we will push process association information in to procstats.
     static final boolean TRACK_PROCSTATS_ASSOCIATIONS = true;
 
@@ -1332,7 +1366,7 @@
     int mProfileType = 0;
     final ProcessMap<Pair<Long, String>> mMemWatchProcesses = new ProcessMap<>();
     String mMemWatchDumpProcName;
-    String mMemWatchDumpFile;
+    Uri mMemWatchDumpUri;
     int mMemWatchDumpPid;
     int mMemWatchDumpUid;
     private boolean mMemWatchIsUserInitiated;
@@ -1344,10 +1378,12 @@
     static final class ProcessChangeItem {
         static final int CHANGE_ACTIVITIES = 1<<0;
         static final int CHANGE_FOREGROUND_SERVICES = 1<<1;
+        static final int CHANGE_CAPABILITY = 1<<2;
         int changes;
         int uid;
         int pid;
         int processState;
+        int capability;
         boolean foregroundActivities;
         int foregroundServiceTypes;
     }
@@ -1519,7 +1555,7 @@
     static final int UPDATE_TIME_PREFERENCE_MSG = 41;
     static final int NOTIFY_CLEARTEXT_NETWORK_MSG = 49;
     static final int POST_DUMP_HEAP_NOTIFICATION_MSG = 50;
-    static final int DELETE_DUMPHEAP_MSG = 51;
+    static final int ABORT_DUMPHEAP_MSG = 51;
     static final int DISPATCH_UIDS_CHANGED_UI_MSG = 53;
     static final int SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG = 56;
     static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG = 57;
@@ -1788,11 +1824,7 @@
                 final boolean isUserInitiated;
                 synchronized (ActivityManagerService.this) {
                     uid = mMemWatchDumpUid;
-                    if (uid == SYSTEM_UID) {
-                        procName = mContext.getString(R.string.android_system_label);
-                    } else {
-                        procName = mMemWatchDumpProcName;
-                    }
+                    procName = mMemWatchDumpProcName;
                     Pair<Long, String> val = mMemWatchProcesses.get(procName, uid);
                     if (val == null) {
                         val = mMemWatchProcesses.get(procName, 0);
@@ -1805,6 +1837,11 @@
                         reportPackage = null;
                     }
                     isUserInitiated = mMemWatchIsUserInitiated;
+
+                    mMemWatchDumpUri = null;
+                    mMemWatchDumpProcName = null;
+                    mMemWatchDumpPid = -1;
+                    mMemWatchDumpUid = -1;
                 }
                 if (procName == null) {
                     return;
@@ -1813,65 +1850,29 @@
                 if (DEBUG_PSS) Slog.d(TAG_PSS,
                         "Showing dump heap notification from " + procName + "/" + uid);
 
-                INotificationManager inm = NotificationManager.getService();
-                if (inm == null) {
-                    return;
-                }
+                Intent dumpFinishedIntent = new Intent(ACTION_HEAP_DUMP_FINISHED);
+                // Send this only to the Shell package.
+                dumpFinishedIntent.setPackage("com.android.shell");
+                dumpFinishedIntent.putExtra(Intent.EXTRA_UID, uid);
+                dumpFinishedIntent.putExtra(EXTRA_HEAP_DUMP_IS_USER_INITIATED, isUserInitiated);
+                dumpFinishedIntent.putExtra(EXTRA_HEAP_DUMP_SIZE_BYTES, memLimit);
+                dumpFinishedIntent.putExtra(EXTRA_HEAP_DUMP_REPORT_PACKAGE, reportPackage);
+                dumpFinishedIntent.putExtra(EXTRA_HEAP_DUMP_PROCESS_NAME, procName);
 
-                final int titleId = isUserInitiated
-                        ? R.string.dump_heap_ready_notification : R.string.dump_heap_notification;
-                String text = mContext.getString(titleId, procName);
-
-                Intent deleteIntent = new Intent();
-                deleteIntent.setAction(DumpHeapActivity.ACTION_DELETE_DUMPHEAP);
-                Intent intent = new Intent();
-                intent.setClassName("android", DumpHeapActivity.class.getName());
-                intent.putExtra(DumpHeapActivity.KEY_PROCESS, procName);
-                intent.putExtra(DumpHeapActivity.KEY_SIZE, memLimit);
-                intent.putExtra(DumpHeapActivity.KEY_IS_USER_INITIATED, isUserInitiated);
-                intent.putExtra(DumpHeapActivity.KEY_IS_SYSTEM_PROCESS, uid == SYSTEM_UID);
-                if (reportPackage != null) {
-                    intent.putExtra(DumpHeapActivity.KEY_DIRECT_LAUNCH, reportPackage);
-                }
-                int userId = UserHandle.getUserId(uid);
-                Notification notification =
-                        new Notification.Builder(mContext, SystemNotificationChannels.DEVELOPER)
-                        .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
-                        .setAutoCancel(true)
-                        .setTicker(text)
-                        .setColor(mContext.getColor(
-                                com.android.internal.R.color.system_notification_accent_color))
-                        .setContentTitle(text)
-                        .setContentText(
-                                mContext.getText(R.string.dump_heap_notification_detail))
-                        .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0,
-                                intent, PendingIntent.FLAG_CANCEL_CURRENT, null,
-                                new UserHandle(userId)))
-                        .setDeleteIntent(PendingIntent.getBroadcastAsUser(mContext, 0,
-                                deleteIntent, 0, UserHandle.SYSTEM))
-                        .build();
-
-                try {
-                    inm.enqueueNotificationWithTag("android", "android", null,
-                            SystemMessage.NOTE_DUMP_HEAP_NOTIFICATION,
-                            notification, userId);
-                } catch (RuntimeException e) {
-                    Slog.w(ActivityManagerService.TAG,
-                            "Error showing notification for dump heap", e);
-                } catch (RemoteException e) {
-                }
+                mContext.sendBroadcastAsUser(dumpFinishedIntent,
+                        UserHandle.getUserHandleForUid(uid));
             } break;
-            case DELETE_DUMPHEAP_MSG: {
-                revokeUriPermission(ActivityThread.currentActivityThread().getApplicationThread(),
-                        null, DumpHeapActivity.JAVA_URI,
-                        Intent.FLAG_GRANT_READ_URI_PERMISSION
-                                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
-                        UserHandle.myUserId());
-                synchronized (ActivityManagerService.this) {
-                    mMemWatchDumpFile = null;
-                    mMemWatchDumpProcName = null;
-                    mMemWatchDumpPid = -1;
-                    mMemWatchDumpUid = -1;
+            case ABORT_DUMPHEAP_MSG: {
+                String procName = (String) msg.obj;
+                if (procName != null) {
+                    synchronized (ActivityManagerService.this) {
+                        if (procName.equals(mMemWatchDumpProcName)) {
+                            mMemWatchDumpProcName = null;
+                            mMemWatchDumpUri = null;
+                            mMemWatchDumpPid = -1;
+                            mMemWatchDumpUid = -1;
+                        }
+                    }
                 }
             } break;
             case SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG: {
@@ -3337,6 +3338,7 @@
                         validateUid.idle = false;
                     }
                     validateUid.setCurProcState(validateUid.setProcState = item.processState);
+                    validateUid.curCapability = validateUid.setCapability = item.capability;
                     validateUid.lastDispatchedProcStateSeq = item.procStateSeq;
                 }
             }
@@ -3402,7 +3404,7 @@
                     if ((reg.which & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
                         if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
                                 "UID CHANGED uid=" + item.uid
-                                        + ": " + item.processState);
+                                        + ": " + item.processState + ": " + item.capability);
                         boolean doReport = true;
                         if (reg.cutpoint >= ActivityManager.MIN_PROCESS_STATE) {
                             final int lastState = reg.lastProcStates.get(item.uid,
@@ -3420,7 +3422,7 @@
                                 reg.lastProcStates.put(item.uid, item.processState);
                             }
                             observer.onUidStateChanged(item.uid, item.processState,
-                                    item.procStateSeq);
+                                    item.procStateSeq, item.capability);
                         }
                     }
                 }
@@ -5245,17 +5247,6 @@
             }
         }, pkgFilter);
 
-        IntentFilter dumpheapFilter = new IntentFilter();
-        dumpheapFilter.addAction(DumpHeapActivity.ACTION_DELETE_DUMPHEAP);
-        mContext.registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                final long delay = intent.getBooleanExtra(
-                        DumpHeapActivity.EXTRA_DELAY_DELETE, false) ? 5 * 60 * 1000 : 0;
-                mHandler.sendEmptyMessageDelayed(DELETE_DUMPHEAP_MSG, delay);
-            }
-        }, dumpheapFilter);
-
         // Inform checkpointing systems of success
         try {
             // This line is needed to CTS test for the correct exception handling
@@ -7758,7 +7749,7 @@
             holder = getContentProviderExternalUnchecked(name, null, callingUid,
                     "*checkContentProviderUriPermission*", userId);
             if (holder != null) {
-                return holder.provider.checkUriPermission(null, uri, callingUid, modeFlags);
+                return holder.provider.checkUriPermission(null, null, uri, callingUid, modeFlags);
             }
         } catch (RemoteException e) {
             Log.w(TAG, "Content provider dead retrieving " + uri, e);
@@ -7923,7 +7914,7 @@
             sCallerIdentity.set(new Identity(
                     token, Binder.getCallingPid(), Binder.getCallingUid()));
             try {
-                pfd = cph.provider.openFile(null, uri, "r", null, token);
+                pfd = cph.provider.openFile(null, null, uri, "r", null, token);
             } catch (FileNotFoundException e) {
                 // do nothing; pfd will be returned null
             } finally {
@@ -10953,7 +10944,7 @@
                 }
             }
             pw.print("  mMemWatchDumpProcName="); pw.println(mMemWatchDumpProcName);
-            pw.print("  mMemWatchDumpFile="); pw.println(mMemWatchDumpFile);
+            pw.print("  mMemWatchDumpUri="); pw.println(mMemWatchDumpUri);
             pw.print("  mMemWatchDumpPid="); pw.println(mMemWatchDumpPid);
             pw.print("  mMemWatchDumpUid="); pw.println(mMemWatchDumpUid);
             pw.print("  mMemWatchIsUserInitiated="); pw.println(mMemWatchIsUserInitiated);
@@ -11250,10 +11241,14 @@
             }
 
             final long dtoken = proto.start(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.DUMP);
-            proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.PROC_NAME, mMemWatchDumpProcName);
-            proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.FILE, mMemWatchDumpFile);
-            proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.PID, mMemWatchDumpPid);
-            proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.UID, mMemWatchDumpUid);
+            proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.PROC_NAME,
+                    mMemWatchDumpProcName);
+            proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.URI,
+                    mMemWatchDumpUri.toString());
+            proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.PID,
+                    mMemWatchDumpPid);
+            proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.UID,
+                    mMemWatchDumpUid);
             proto.write(
                     ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.IS_USER_INITIATED,
                     mMemWatchIsUserInitiated);
@@ -16366,9 +16361,10 @@
         }
     }
 
-    void noteUidProcessState(final int uid, final int state) {
+    void noteUidProcessState(final int uid, final int state,
+                final @ActivityManager.ProcessCapability int capability) {
         mBatteryStatsService.noteUidProcessState(uid, state);
-        mAppOpsService.updateUidProcState(uid, state);
+        mAppOpsService.updateUidProcState(uid, state, capability);
         if (mTrackingAssociations) {
             for (int i1=0, N1=mAssociations.size(); i1<N1; i1++) {
                 ArrayMap<ComponentName, SparseArray<ArrayMap<String, Association>>> targetComponents
@@ -16395,56 +16391,44 @@
         }
     }
 
-    private static final class RecordPssRunnable implements Runnable {
-        private final ActivityManagerService mService;
-        private final ProcessRecord mProc;
-        private final File mHeapdumpFile;
+    /** @hide */
+    public static Uri makeHeapDumpUri(String procName) {
+        return Uri.parse("content://com.android.shell.heapdump/" + procName + "_javaheap.bin");
+    }
 
-        RecordPssRunnable(ActivityManagerService service, ProcessRecord proc, File heapdumpFile) {
-            this.mService = service;
-            this.mProc = proc;
-            this.mHeapdumpFile = heapdumpFile;
+    private final class RecordPssRunnable implements Runnable {
+        private final ProcessRecord mProc;
+        private final Uri mDumpUri;
+        private final ContentResolver mContentResolver;
+
+        RecordPssRunnable(ProcessRecord proc, Uri dumpUri, ContentResolver contentResolver) {
+            mProc = proc;
+            mDumpUri = dumpUri;
+            mContentResolver = contentResolver;
         }
 
         @Override
         public void run() {
-            mService.revokeUriPermission(ActivityThread.currentActivityThread()
-                            .getApplicationThread(),
-                    null, DumpHeapActivity.JAVA_URI,
-                    Intent.FLAG_GRANT_READ_URI_PERMISSION
-                            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
-                    UserHandle.myUserId());
-            ParcelFileDescriptor fd = null;
-            try {
-                mHeapdumpFile.delete();
-                fd = ParcelFileDescriptor.open(mHeapdumpFile,
-                        ParcelFileDescriptor.MODE_CREATE
-                        | ParcelFileDescriptor.MODE_TRUNCATE
-                        | ParcelFileDescriptor.MODE_WRITE_ONLY
-                        | ParcelFileDescriptor.MODE_APPEND);
+            try (ParcelFileDescriptor fd = mContentResolver.openFileDescriptor(mDumpUri, "rw")) {
                 IApplicationThread thread = mProc.thread;
                 if (thread != null) {
                     try {
                         if (DEBUG_PSS) {
                             Slog.d(TAG_PSS, "Requesting dump heap from "
-                                    + mProc + " to " + mHeapdumpFile);
+                                    + mProc + " to " + mDumpUri.getPath());
                         }
                         thread.dumpHeap(/* managed= */ true,
                                 /* mallocInfo= */ false, /* runGc= */ false,
-                                mHeapdumpFile.toString(), fd,
+                                mDumpUri.getPath(), fd,
                                 /* finishCallback= */ null);
                     } catch (RemoteException e) {
                     }
                 }
-            } catch (FileNotFoundException e) {
-                e.printStackTrace();
-            } finally {
-                if (fd != null) {
-                    try {
-                        fd.close();
-                    } catch (IOException e) {
-                    }
-                }
+            } catch (IOException e) {
+                Slog.e(TAG, "Failed to dump heap", e);
+                // Need to clear the heap dump variables, otherwise no further heap dumps will be
+                // attempted.
+                abortHeapDump(mProc.processName);
             }
         }
     }
@@ -16513,13 +16497,20 @@
     }
 
     private void startHeapDumpLocked(ProcessRecord proc, boolean isUserInitiated) {
-        final File heapdumpFile = DumpHeapProvider.getJavaFile();
         mMemWatchDumpProcName = proc.processName;
-        mMemWatchDumpFile = heapdumpFile.toString();
+        mMemWatchDumpUri = makeHeapDumpUri(proc.processName);
         mMemWatchDumpPid = proc.pid;
         mMemWatchDumpUid = proc.uid;
         mMemWatchIsUserInitiated = isUserInitiated;
-        BackgroundThread.getHandler().post(new RecordPssRunnable(this, proc, heapdumpFile));
+        Context ctx;
+        try {
+            ctx = mContext.createPackageContextAsUser("android", 0,
+                    UserHandle.getUserHandleForUid(mMemWatchDumpUid));
+        } catch (NameNotFoundException e) {
+            throw new RuntimeException("android package not found.");
+        }
+        BackgroundThread.getHandler().post(
+                new RecordPssRunnable(proc, mMemWatchDumpUri, ctx.getContentResolver()));
     }
 
     /**
@@ -16891,6 +16882,7 @@
         }
         pendingChange.change = change;
         pendingChange.processState = uidRec != null ? uidRec.setProcState : PROCESS_STATE_NONEXISTENT;
+        pendingChange.capability = uidRec != null ? uidRec.setCapability : 0;
         pendingChange.ephemeral = uidRec != null ? uidRec.ephemeral : isEphemeralLocked(uid);
         pendingChange.procStateSeq = uidRec != null ? uidRec.curProcStateSeq : 0;
         if (uidRec != null) {
@@ -17715,9 +17707,9 @@
                         + " does not match last pid " + mMemWatchDumpPid);
                 return;
             }
-            if (mMemWatchDumpFile == null || !mMemWatchDumpFile.equals(path)) {
+            if (mMemWatchDumpUri == null || !mMemWatchDumpUri.getPath().equals(path)) {
                 Slog.w(TAG, "dumpHeapFinished: Calling path " + path
-                        + " does not match last path " + mMemWatchDumpFile);
+                        + " does not match last path " + mMemWatchDumpUri);
                 return;
             }
             if (DEBUG_PSS) Slog.d(TAG_PSS, "Dump heap finished for " + path);
@@ -17728,6 +17720,13 @@
         }
     }
 
+    /** Clear the currently executing heap dump variables so a new heap dump can be started. */
+    private void abortHeapDump(String procName) {
+        Message msg = mHandler.obtainMessage(ABORT_DUMPHEAP_MSG);
+        msg.obj = procName;
+        mHandler.sendMessage(msg);
+    }
+
     /** In this method we try to acquire our lock to make sure that we have not deadlocked */
     public void monitor() {
         synchronized (this) { }
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 8be2438..59acdcf 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -1470,7 +1470,8 @@
         }
 
         @Override
-        public void onUidStateChanged(int uid, int procState, long procStateSeq) throws RemoteException {
+        public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability)
+                throws RemoteException {
             synchronized (this) {
                 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
                 try {
@@ -1478,7 +1479,9 @@
                     mPw.print(" procstate ");
                     mPw.print(ProcessList.makeProcStateString(procState));
                     mPw.print(" seq ");
-                    mPw.println(procStateSeq);
+                    mPw.print(procStateSeq);
+                    mPw.print(" capability ");
+                    mPw.println(capability);
                     mPw.flush();
                 } finally {
                     StrictMode.setThreadPolicy(oldPolicy);
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 6a29c75..8095020 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -383,7 +383,11 @@
             // and then the delayed summary kill will be a no-op.
             final ProcessRecord p = proc;
             mService.mHandler.postDelayed(
-                    () -> killAppImmediateLocked(p, "forced", "killed for invalid state"),
+                    () -> {
+                        synchronized (mService) {
+                            killAppImmediateLocked(p, "forced", "killed for invalid state");
+                        }
+                    },
                     5000L);
         }
     }
diff --git a/services/core/java/com/android/server/am/DumpHeapProvider.java b/services/core/java/com/android/server/am/DumpHeapProvider.java
deleted file mode 100644
index a8b639e..0000000
--- a/services/core/java/com/android/server/am/DumpHeapProvider.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.am;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Environment;
-import android.os.ParcelFileDescriptor;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-
-public class DumpHeapProvider extends ContentProvider {
-    static final Object sLock = new Object();
-    static File sHeapDumpJavaFile;
-
-    static public File getJavaFile() {
-        synchronized (sLock) {
-            return sHeapDumpJavaFile;
-        }
-    }
-
-    @Override
-    public boolean onCreate() {
-        synchronized (sLock) {
-            File dataDir = Environment.getDataDirectory();
-            File systemDir = new File(dataDir, "system");
-            File heapdumpDir = new File(systemDir, "heapdump");
-            heapdumpDir.mkdir();
-            sHeapDumpJavaFile = new File(heapdumpDir, "javaheap.bin");
-        }
-        return true;
-    }
-
-    @Override
-    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
-        return null;
-    }
-
-    @Override
-    public String getType(Uri uri) {
-        return "application/octet-stream";
-    }
-
-    @Override
-    public Uri insert(Uri uri, ContentValues values) {
-        return null;
-    }
-
-    @Override
-    public int delete(Uri uri, String selection, String[] selectionArgs) {
-        return 0;
-    }
-
-    @Override
-    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
-        return 0;
-    }
-
-    @Override
-    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
-        synchronized (sLock) {
-            String path = uri.getEncodedPath();
-            final String tag = Uri.decode(path);
-            if (tag.equals("/java")) {
-                return ParcelFileDescriptor.open(sHeapDumpJavaFile,
-                        ParcelFileDescriptor.MODE_READ_ONLY);
-            } else {
-                throw new FileNotFoundException("Invalid path for " + uri);
-            }
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 78a9efc..30674db 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -16,6 +16,9 @@
 
 package com.android.server.am;
 
+import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
 import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
 import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
 import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
@@ -23,7 +26,6 @@
 import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
 import static android.app.ActivityManager.PROCESS_STATE_CACHED_RECENT;
 import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
-import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION;
 import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
 import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
 import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
@@ -65,6 +67,7 @@
 import android.app.usage.UsageEvents;
 import android.content.Context;
 import android.content.pm.ServiceInfo;
+import android.os.Build;
 import android.os.Debug;
 import android.os.Handler;
 import android.os.IBinder;
@@ -407,6 +410,13 @@
             mAdjSeq--;
             // Update these reachable processes
             updateOomAdjLockedInner(oomAdjReason, topApp, processes, uids, false);
+        } else if (app.getCurRawAdj() == ProcessList.UNKNOWN_ADJ) {
+            // In case the app goes from non-cached to cached but it doesn't have other reachable
+            // processes, its adj could be still unknown as of now, assign one.
+            processes.add(app);
+            assignCachedAdjIfNecessary(processes);
+            applyOomAdjLocked(app, false, SystemClock.uptimeMillis(),
+                    SystemClock.elapsedRealtime());
         }
         mService.mOomAdjProfiler.oomAdjEnded();
         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
@@ -471,6 +481,7 @@
             app.containsCycle = false;
             app.setCurRawProcState(PROCESS_STATE_CACHED_EMPTY);
             app.setCurRawAdj(ProcessList.UNKNOWN_ADJ);
+            app.setCapability = PROCESS_CAPABILITY_NONE;
             app.resetCachedInfo();
         }
         for (int i = numProc - 1; i >= 0; i--) {
@@ -486,7 +497,7 @@
             }
         }
 
-        assignCachedAdjIfNecessary();
+        assignCachedAdjIfNecessary(mProcessList.mLruProcesses);
 
         if (fullUpdate) { // There won't be cycles if we didn't compute clients above.
             // Cycle strategy:
@@ -560,8 +571,7 @@
         }
     }
 
-    private void assignCachedAdjIfNecessary() {
-        ArrayList<ProcessRecord> lruList = mProcessList.mLruProcesses;
+    private void assignCachedAdjIfNecessary(ArrayList<ProcessRecord> lruList) {
         final int numLru = lruList.size();
 
         // First update the OOM adjustment for each of the
@@ -788,6 +798,7 @@
             if (app.hasForegroundServices()) {
                 uidRec.foregroundServices = true;
             }
+            uidRec.curCapability |= app.curCapability;
         }
     }
 
@@ -804,10 +815,13 @@
             int uidChange = UidRecord.CHANGE_PROCSTATE;
             if (uidRec.getCurProcState() != PROCESS_STATE_NONEXISTENT
                     && (uidRec.setProcState != uidRec.getCurProcState()
+                    || uidRec.setCapability != uidRec.curCapability
                     || uidRec.setWhitelist != uidRec.curWhitelist)) {
                 if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, "Changes in " + uidRec
                         + ": proc state from " + uidRec.setProcState + " to "
-                        + uidRec.getCurProcState() + ", whitelist from " + uidRec.setWhitelist
+                        + uidRec.getCurProcState() + ", capability from "
+                        + uidRec.setCapability + " to " + uidRec.curCapability
+                        + ", whitelist from " + uidRec.setWhitelist
                         + " to " + uidRec.curWhitelist);
                 if (ActivityManager.isProcStateBackground(uidRec.getCurProcState())
                         && !uidRec.curWhitelist) {
@@ -845,11 +859,13 @@
                     uidChange |= isCached ? UidRecord.CHANGE_CACHED : UidRecord.CHANGE_UNCACHED;
                 }
                 uidRec.setProcState = uidRec.getCurProcState();
+                uidRec.setCapability = uidRec.curCapability;
                 uidRec.setWhitelist = uidRec.curWhitelist;
                 uidRec.setIdle = uidRec.idle;
                 mService.mAtmInternal.onUidProcStateChanged(uidRec.uid, uidRec.setProcState);
                 mService.enqueueUidChangeLocked(uidRec, -1, uidChange);
-                mService.noteUidProcessState(uidRec.uid, uidRec.getCurProcState());
+                mService.noteUidProcessState(uidRec.uid, uidRec.getCurProcState(),
+                        uidRec.curCapability);
                 if (uidRec.foregroundServices) {
                     mService.mServices.foregroundServiceProcStateChangedLocked(uidRec);
                 }
@@ -1016,6 +1032,7 @@
             app.curAdj = ProcessList.CACHED_APP_MAX_ADJ;
             app.setCurRawAdj(ProcessList.CACHED_APP_MAX_ADJ);
             app.completedAdjSeq = app.adjSeq;
+            app.curCapability = PROCESS_CAPABILITY_NONE;
             return false;
         }
 
@@ -1030,6 +1047,7 @@
 
         int prevAppAdj = app.curAdj;
         int prevProcState = app.getCurProcState();
+        int prevCapability = app.curCapability;
 
         if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {
             // The max adjustment doesn't allow this app to be anything
@@ -1087,6 +1105,7 @@
         int schedGroup;
         int procState;
         int cachedAdjSeq;
+        int capability = 0;
 
         boolean foregroundActivities = false;
         if (PROCESS_STATE_CUR_TOP == PROCESS_STATE_TOP && app == topApp) {
@@ -1185,19 +1204,17 @@
             }
         }
 
+        if (app.hasLocationForegroundServices()) {
+            capability |= PROCESS_CAPABILITY_FOREGROUND_LOCATION;
+        }
+
         if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
-                || procState > PROCESS_STATE_FOREGROUND_SERVICE_LOCATION) {
+                || procState > PROCESS_STATE_FOREGROUND_SERVICE) {
             if (app.hasForegroundServices()) {
                 // The user is aware of this app, so make it visible.
                 adj = ProcessList.PERCEPTIBLE_APP_ADJ;
-                if (app.hasLocationForegroundServices()) {
-                    procState = PROCESS_STATE_FOREGROUND_SERVICE_LOCATION;
-                    app.adjType = "fg-service-location";
-
-                } else {
-                    procState = PROCESS_STATE_FOREGROUND_SERVICE;
-                    app.adjType = "fg-service";
-                }
+                procState = PROCESS_STATE_FOREGROUND_SERVICE;
+                app.adjType = "fg-service";
                 app.cached = false;
                 schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
@@ -1437,6 +1454,10 @@
                             continue;
                         }
 
+                        if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
+                            capability |= client.curCapability;
+                        }
+
                         int clientAdj = client.getCurRawAdj();
                         int clientProcState = client.getCurRawProcState();
 
@@ -1549,25 +1570,31 @@
                                 // processes).  These should not bring the current process
                                 // into the top state, since they are not on top.  Instead
                                 // give them the best bound state after that.
-                                final int bestState = cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)
-                                        ? PROCESS_STATE_FOREGROUND_SERVICE_LOCATION
-                                        : PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
-                                if ((cr.flags & Context.BIND_FOREGROUND_SERVICE) != 0) {
-                                    clientProcState = bestState;
+                                if (cr.hasFlag(Context.BIND_FOREGROUND_SERVICE)) {
+                                    clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;                                                                                                                       ;
                                 } else if (mService.mWakefulness
                                         == PowerManagerInternal.WAKEFULNESS_AWAKE
                                         && (cr.flags & Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)
                                                 != 0) {
-                                    clientProcState = bestState;
+                                    clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
                                 } else {
                                     clientProcState =
                                             PROCESS_STATE_IMPORTANT_FOREGROUND;
                                 }
                             } else if (clientProcState == PROCESS_STATE_TOP) {
-                                if (cr.notHasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
-                                    // Go at most to BOUND_TOP, unless requested to elevate
-                                    // to client's state.
-                                    clientProcState = PROCESS_STATE_BOUND_TOP;
+                                // Go at most to BOUND_TOP, unless requested to elevate
+                                // to client's state.
+                                clientProcState = PROCESS_STATE_BOUND_TOP;
+                                if (client.info.targetSdkVersion >= Build.VERSION_CODES.R) {
+                                    if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
+                                        // TOP process passes all capabilities to the service.
+                                        capability = PROCESS_CAPABILITY_ALL;
+                                    } else {
+                                        // TOP process passes no capability to the service.
+                                    }
+                                } else {
+                                    // TOP process passes all capabilities to the service.
+                                    capability = PROCESS_CAPABILITY_ALL;
                                 }
                             } else if (clientProcState
                                     <= PROCESS_STATE_FOREGROUND_SERVICE) {
@@ -1852,12 +1879,18 @@
             }
         }
 
+        // TOP process has all capabilities.
+        if (procState <= PROCESS_STATE_TOP) {
+            capability = PROCESS_CAPABILITY_ALL;
+        }
+
         // Do final modification to adj.  Everything we do between here and applying
         // the final setAdj must be done in this function, because we will also use
         // it when computing the final cached adj later.  Note that we don't need to
         // worry about this for max adj above, since max adj will always be used to
         // keep it out of the cached vaues.
         app.curAdj = app.modifyRawOomAdj(adj);
+        app.curCapability = capability;
         app.setCurrentSchedulingGroup(schedGroup);
         app.setCurProcState(procState);
         app.setCurRawProcState(procState);
@@ -1865,7 +1898,8 @@
         app.completedAdjSeq = mAdjSeq;
 
         // if curAdj or curProcState improved, then this process was promoted
-        return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState;
+        return app.curAdj < prevAppAdj || app.getCurProcState() < prevProcState
+                || app.curCapability != prevCapability ;
     }
 
     /**
@@ -2175,6 +2209,11 @@
             maybeUpdateUsageStatsLocked(app, nowElapsed);
         }
 
+        if (app.curCapability != app.setCapability) {
+            changes |= ActivityManagerService.ProcessChangeItem.CHANGE_CAPABILITY;
+            app.setCapability = app.curCapability;
+        }
+
         if (changes != 0) {
             if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                     "Changes in " + app + ": " + changes);
@@ -2182,12 +2221,13 @@
                     mService.enqueueProcessChangeItemLocked(app.pid, app.info.uid);
             item.changes = changes;
             item.foregroundActivities = app.repForegroundActivities;
+            item.capability = app.setCapability;
             if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                     "Item " + Integer.toHexString(System.identityHashCode(item))
                             + " " + app.toShortString() + ": changes=" + item.changes
                             + " foreground=" + item.foregroundActivities
                             + " type=" + app.adjType + " source=" + app.adjSource
-                            + " target=" + app.adjTarget);
+                            + " target=" + app.adjTarget + " capability=" + item.capability);
         }
 
         return success;
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 54504c3..3ba2210 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -508,7 +508,7 @@
         }
         if (key.requestIntent != null) {
             pw.print(prefix); pw.print("requestIntent=");
-                    pw.println(key.requestIntent.toShortString(false, true, true, true));
+                    pw.println(key.requestIntent.toShortString(false, true, true, false));
         }
         if (sent || canceled) {
             pw.print(prefix); pw.print("sent="); pw.print(sent);
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 8163a6d..8be31a6 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -810,9 +810,6 @@
             case ActivityManager.PROCESS_STATE_TOP:
                 procState = "TOP ";
                 break;
-            case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION:
-                procState = "FGSL";
-                break;
             case ActivityManager.PROCESS_STATE_BOUND_TOP:
                 procState = "BTOP";
                 break;
@@ -882,8 +879,6 @@
                 return AppProtoEnums.PROCESS_STATE_PERSISTENT_UI;
             case ActivityManager.PROCESS_STATE_TOP:
                 return AppProtoEnums.PROCESS_STATE_TOP;
-            case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION:
-                return AppProtoEnums.PROCESS_STATE_FOREGROUND_SERVICE;
             case ActivityManager.PROCESS_STATE_BOUND_TOP:
                 return AppProtoEnums.PROCESS_STATE_BOUND_TOP;
             case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE:
@@ -1014,7 +1009,6 @@
         PROC_MEM_PERSISTENT,            // ActivityManager.PROCESS_STATE_PERSISTENT
         PROC_MEM_PERSISTENT,            // ActivityManager.PROCESS_STATE_PERSISTENT_UI
         PROC_MEM_TOP,                   // ActivityManager.PROCESS_STATE_TOP
-        PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION
         PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
         PROC_MEM_TOP,                   // ActivityManager.PROCESS_STATE_BOUND_TOP
         PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
@@ -1329,7 +1323,7 @@
             final int procCount = procs.size();
             for (int i = 0; i < procCount; i++) {
                 final int procUid = procs.keyAt(i);
-                if (UserHandle.isApp(procUid) || !UserHandle.isSameUser(procUid, uid)) {
+                if (!UserHandle.isCore(procUid) || !UserHandle.isSameUser(procUid, uid)) {
                     // Don't use an app process or different user process for system component.
                     continue;
                 }
@@ -2303,7 +2297,8 @@
             uidRec.updateHasInternetPermission();
             mActiveUids.put(proc.uid, uidRec);
             EventLogTags.writeAmUidRunning(uidRec.uid);
-            mService.noteUidProcessState(uidRec.uid, uidRec.getCurProcState());
+            mService.noteUidProcessState(uidRec.uid, uidRec.getCurProcState(),
+                    uidRec.curCapability);
         }
         proc.uidRecord = uidRec;
 
@@ -2405,7 +2400,8 @@
                 mService.enqueueUidChangeLocked(old.uidRecord, -1, UidRecord.CHANGE_GONE);
                 EventLogTags.writeAmUidStopped(uid);
                 mActiveUids.remove(uid);
-                mService.noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT);
+                mService.noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT,
+                        ActivityManager.PROCESS_CAPABILITY_NONE);
             }
             old.uidRecord = null;
         }
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index bf43f3b..1e0693f 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -151,6 +151,9 @@
     int curAdj;                 // Current OOM adjustment for this process
     int setAdj;                 // Last set OOM adjustment for this process
     int verifiedAdj;            // The last adjustment that was verified as actually being set
+    int curCapability;          // Current capability flags of this process. For example,
+                                // PROCESS_CAPABILITY_FOREGROUND_LOCATION is one capability.
+    int setCapability;          // Last set capability flags.
     long lastCompactTime;       // The last time that this process was compacted
     int reqCompactAction;       // The most recent compaction action requested for this app.
     int lastCompactAction;      // The most recent compaction action performed for this app.
@@ -425,6 +428,8 @@
                 pw.print(" mRepProcState="); pw.print(mRepProcState);
                 pw.print(" pssProcState="); pw.print(pssProcState);
                 pw.print(" setProcState="); pw.print(setProcState);
+                pw.print(" curCapability="); pw.print(curCapability);
+                pw.print(" setCapability="); pw.print(setCapability);
                 pw.print(" lastStateTime=");
                 TimeUtils.formatDuration(lastStateTime, nowUptime, pw);
                 pw.println();
@@ -1097,6 +1102,10 @@
                 && (mFgServiceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION) != 0;
     }
 
+    boolean hasLocationCapability() {
+        return (setCapability & ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0;
+    }
+
     int getForegroundServiceTypes() {
         return mHasForegroundServices ? mFgServiceTypes : 0;
     }
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index cc4b160..5106b0e 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -256,7 +256,7 @@
         }
         if (intent != null) {
             intent.getIntent().writeToProto(proto, ServiceRecordProto.INTENT, false, true, false,
-                    true);
+                    false);
         }
         proto.write(ServiceRecordProto.PACKAGE_NAME, packageName);
         proto.write(ServiceRecordProto.PROCESS_NAME, processName);
@@ -358,7 +358,7 @@
 
     void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("intent={");
-                pw.print(intent.getIntent().toShortString(false, true, false, true));
+                pw.print(intent.getIntent().toShortString(false, true, false, false));
                 pw.println('}');
         pw.print(prefix); pw.print("packageName="); pw.println(packageName);
         pw.print(prefix); pw.print("processName="); pw.println(processName);
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index 22a7de7..e6cf287 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -34,6 +34,8 @@
     final int uid;
     private int mCurProcState;
     int setProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
+    int curCapability;
+    int setCapability;
     long lastBackgroundTime;
     boolean ephemeral;
     boolean foregroundServices;
@@ -108,6 +110,7 @@
         int uid;
         int change;
         int processState;
+        int capability;
         boolean ephemeral;
         long procStateSeq;
     }
@@ -132,6 +135,8 @@
     public void reset() {
         setCurProcState(ActivityManager.PROCESS_STATE_CACHED_EMPTY);
         foregroundServices = false;
+        curCapability = 0;
+
     }
 
     public void updateHasInternetPermission() {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 17541911..0ea913f 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -560,8 +560,8 @@
             Slog.i(TAG, "Stopping pre-created user " + userInfo.toFullString());
             // Pre-created user was started right after creation so services could properly
             // intialize it; it should be stopped right away as it's not really a "real" user.
-            // TODO(b/140750212): in the long-term, we should add a onCreateUser() callback
-            // on SystemService instead.
+            // TODO(b/143092698): in the long-term, it might be better to add a onCreateUser()
+            // callback on SystemService instead.
             stopUser(userInfo.id, /* force= */ true, /* stopUserCallback= */ null,
                     /* keyEvictedCallback= */ null);
             return;
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 8575068..2e36a43 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.appop;
 
+import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
 import static android.app.AppOpsManager.MAX_PRIORITY_UID_STATE;
 import static android.app.AppOpsManager.MIN_PRIORITY_UID_STATE;
 import static android.app.AppOpsManager.OP_CAMERA;
@@ -27,7 +28,6 @@
 import static android.app.AppOpsManager.UID_STATE_CACHED;
 import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
 import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
-import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE_LOCATION;
 import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
 import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
 import static android.app.AppOpsManager.UID_STATE_TOP;
@@ -119,12 +119,6 @@
 import com.android.server.LocalServices;
 import com.android.server.LockGuard;
 
-import libcore.util.EmptyArray;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
@@ -144,6 +138,12 @@
 import java.util.Map;
 import java.util.Objects;
 
+import libcore.util.EmptyArray;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
 public class AppOpsService extends IAppOpsService.Stub {
     static final String TAG = "AppOps";
     static final boolean DEBUG = false;
@@ -164,12 +164,10 @@
         UID_STATE_PERSISTENT,           // ActivityManager.PROCESS_STATE_PERSISTENT
         UID_STATE_PERSISTENT,           // ActivityManager.PROCESS_STATE_PERSISTENT_UI
         UID_STATE_TOP,                  // ActivityManager.PROCESS_STATE_TOP
-        UID_STATE_FOREGROUND_SERVICE_LOCATION,
-                                        // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION
         UID_STATE_FOREGROUND,           // ActivityManager.PROCESS_STATE_BOUND_TOP
         UID_STATE_FOREGROUND_SERVICE,   // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
         UID_STATE_FOREGROUND,           // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
-        UID_STATE_FOREGROUND,           // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+        UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
         UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
         UID_STATE_BACKGROUND,           // ActivityManager.PROCESS_STATE_BACKUP
@@ -364,7 +362,8 @@
         public int state = UID_STATE_CACHED;
         public int pendingState = UID_STATE_CACHED;
         public long pendingStateCommitTime;
-
+        public int capability;
+        public int pendingCapability;
         // For all features combined
         public int startNesting;
 
@@ -393,8 +392,25 @@
 
         int evalMode(int op, int mode) {
             if (mode == AppOpsManager.MODE_FOREGROUND) {
-                return state <= AppOpsManager.resolveFirstUnrestrictedUidState(op)
-                        ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
+                if (state <= UID_STATE_TOP) {
+                    // process is in foreground.
+                    return AppOpsManager.MODE_ALLOWED;
+                } else if (state <= AppOpsManager.resolveFirstUnrestrictedUidState(op)) {
+                    // process is in foreground, check its capability.
+                    switch (op) {
+                        case AppOpsManager.OP_FINE_LOCATION:
+                        case AppOpsManager.OP_COARSE_LOCATION:
+                        case AppOpsManager.OP_MONITOR_LOCATION:
+                        case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION:
+                            return ((capability & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0)
+                                ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
+                        default:
+                            return AppOpsManager.MODE_ALLOWED;
+                    }
+                } else {
+                    // process is not in foreground.
+                    return AppOpsManager.MODE_IGNORED;
+                }
             }
             return mode;
         }
@@ -1062,13 +1078,16 @@
         }
     }
 
-    public void updateUidProcState(int uid, int procState) {
+    public void updateUidProcState(int uid, int procState,
+            @ActivityManager.ProcessCapability int capability) {
         synchronized (this) {
             final UidState uidState = getUidStateLocked(uid, true);
-            int newState = PROCESS_STATE_TO_UID_STATE[procState];
-            if (uidState != null && uidState.pendingState != newState) {
+            final int newState = PROCESS_STATE_TO_UID_STATE[procState];
+            if (uidState != null && (uidState.pendingState != newState
+                    || uidState.pendingCapability != capability)) {
                 final int oldPendingState = uidState.pendingState;
                 uidState.pendingState = newState;
+                uidState.pendingCapability = capability;
                 if (newState < uidState.state
                         || (newState <= UID_STATE_MAX_LAST_NON_RESTRICTED
                                 && uidState.state > UID_STATE_MAX_LAST_NON_RESTRICTED)) {
@@ -1076,6 +1095,9 @@
                     // foreground and the old state is in the background, then always do it
                     // immediately.
                     commitUidPendingStateLocked(uidState);
+                } else if (newState == uidState.state && capability != uidState.capability) {
+                    // No change on process state, but process capability has changed.
+                    commitUidPendingStateLocked(uidState);
                 } else if (uidState.pendingStateCommitTime == 0) {
                     // We are moving to a less important state for the first time,
                     // delay the application for a bit.
@@ -1182,8 +1204,8 @@
             }
         } else {
             for (int j=0; j<ops.length; j++) {
-                int code = uidState.opModes.keyAt(j);
-                if (code >= 0) {
+                int code = ops[j];
+                if (uidState.opModes.indexOfKey(code) >= 0) {
                     if (resOps == null) {
                         resOps = new ArrayList<>();
                     }
@@ -2857,6 +2879,7 @@
             }
         }
         uidState.state = uidState.pendingState;
+        uidState.capability = uidState.pendingCapability;
         uidState.pendingStateCommitTime = 0;
     }
 
@@ -4494,6 +4517,12 @@
                     pw.print("    pendingState=");
                     pw.println(AppOpsManager.getUidStateName(uidState.pendingState));
                 }
+                pw.print("    capability=");
+                pw.println(uidState.capability);
+                if (uidState.capability != uidState.pendingCapability) {
+                    pw.print("    pendingCapability=");
+                    pw.println(uidState.pendingCapability);
+                }
                 if (uidState.pendingStateCommitTime != 0) {
                     pw.print("    pendingStateCommitTime=");
                     TimeUtils.formatDuration(uidState.pendingStateCommitTime, nowElapsed, pw);
diff --git a/services/core/java/com/android/server/appop/TEST_MAPPING b/services/core/java/com/android/server/appop/TEST_MAPPING
index e9d2b31..9c03a36 100644
--- a/services/core/java/com/android/server/appop/TEST_MAPPING
+++ b/services/core/java/com/android/server/appop/TEST_MAPPING
@@ -35,6 +35,9 @@
                     "include-filter": "android.permission.cts.SharedUidPermissionsTest"
                 }
             ]
+        },
+        {
+            "name": "CtsAppTestCases:ActivityManagerApi29Test"
         }
     ]
 }
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index 087c84f..232bc08e 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -21,9 +21,9 @@
 import static android.service.attention.AttentionService.ATTENTION_FAILURE_UNKNOWN;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
-import android.app.ActivityManager;
 import android.attention.AttentionManagerInternal;
 import android.attention.AttentionManagerInternal.AttentionCallbackInternal;
 import android.content.BroadcastReceiver;
@@ -86,6 +86,10 @@
     /** If the check attention called within that period - cached value will be returned. */
     private static final long STALE_AFTER_MILLIS = 5_000;
 
+    /** The size of the buffer that stores recent attention check results. */
+    @VisibleForTesting
+    protected static final int ATTENTION_CACHE_BUFFER_SIZE = 5;
+
     /** DeviceConfig flag name, if {@code true}, enables AttentionManagerService features. */
     private static final String SERVICE_ENABLED = "service_enabled";
     private static String sTestAttentionServicePackage;
@@ -193,7 +197,8 @@
             userState.bindLocked();
 
             // throttle frequent requests
-            final AttentionCheckCache cache = userState.mAttentionCheckCache;
+            final AttentionCheckCache cache = userState.mAttentionCheckCacheBuffer == null ? null
+                    : userState.mAttentionCheckCacheBuffer.getLast();
             if (cache != null && now < cache.mLastComputed + STALE_AFTER_MILLIS) {
                 callbackInternal.onSuccess(cache.mResult, cache.mTimestamp);
                 return true;
@@ -237,9 +242,11 @@
                 }
 
                 synchronized (mLock) {
-                    userState.mAttentionCheckCache = new AttentionCheckCache(
-                            SystemClock.uptimeMillis(), result,
-                            timestamp);
+                    if (userState.mAttentionCheckCacheBuffer == null) {
+                        userState.mAttentionCheckCacheBuffer = new AttentionCheckCacheBuffer();
+                    }
+                    userState.mAttentionCheckCacheBuffer.add(
+                            new AttentionCheckCache(SystemClock.uptimeMillis(), result, timestamp));
                 }
                 StatsLog.write(
                         StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED,
@@ -300,7 +307,8 @@
     @GuardedBy("mLock")
     @VisibleForTesting
     protected UserState getOrCreateCurrentUserStateLocked() {
-        return getOrCreateUserStateLocked(ActivityManager.getCurrentUser());
+        // Doesn't need to cache the states of different users.
+        return getOrCreateUserStateLocked(0);
     }
 
     @GuardedBy("mLock")
@@ -318,7 +326,8 @@
     @Nullable
     @VisibleForTesting
     protected UserState peekCurrentUserStateLocked() {
-        return peekUserStateLocked(ActivityManager.getCurrentUser());
+        // Doesn't need to cache the states of different users.
+        return peekUserStateLocked(0);
     }
 
     @GuardedBy("mLock")
@@ -420,7 +429,41 @@
         }
     }
 
-    private static final class AttentionCheckCache {
+    @VisibleForTesting
+    protected static final class AttentionCheckCacheBuffer {
+        private final AttentionCheckCache[] mQueue;
+        private int mStartIndex;
+        private int mSize;
+
+        AttentionCheckCacheBuffer() {
+            mQueue = new AttentionCheckCache[ATTENTION_CACHE_BUFFER_SIZE];
+            mStartIndex = 0;
+            mSize = 0;
+        }
+
+        public AttentionCheckCache getLast() {
+            int lastIdx = (mStartIndex + mSize - 1) % ATTENTION_CACHE_BUFFER_SIZE;
+            return mSize == 0 ? null : mQueue[lastIdx];
+        }
+
+        public void add(@NonNull AttentionCheckCache cache) {
+            int nextIndex = (mStartIndex + mSize) % ATTENTION_CACHE_BUFFER_SIZE;
+            mQueue[nextIndex] = cache;
+            if (mSize == ATTENTION_CACHE_BUFFER_SIZE) {
+                mStartIndex++;
+            } else {
+                mSize++;
+            }
+        }
+
+        public AttentionCheckCache get(int offset) {
+            return offset >= mSize ? null
+                    : mQueue[(mStartIndex + offset) % ATTENTION_CACHE_BUFFER_SIZE];
+        }
+    }
+
+    @VisibleForTesting
+    protected static final class AttentionCheckCache {
         private final long mLastComputed;
         private final int mResult;
         private final long mTimestamp;
@@ -462,7 +505,7 @@
         @GuardedBy("mLock")
         AttentionCheck mCurrentAttentionCheck;
         @GuardedBy("mLock")
-        AttentionCheckCache mAttentionCheckCache;
+        AttentionCheckCacheBuffer mAttentionCheckCacheBuffer;
         @GuardedBy("mLock")
         private boolean mBinding;
 
@@ -531,13 +574,14 @@
                     pw.println("is fulfilled:=" + mCurrentAttentionCheck.mIsFulfilled);
                     pw.decreaseIndent();
                 }
-                pw.println("attention check cache:");
-                if (mAttentionCheckCache != null) {
-                    pw.increaseIndent();
-                    pw.println("last computed=" + mAttentionCheckCache.mLastComputed);
-                    pw.println("timestamp=" + mAttentionCheckCache.mTimestamp);
-                    pw.println("result=" + mAttentionCheckCache.mResult);
-                    pw.decreaseIndent();
+                if (mAttentionCheckCacheBuffer != null) {
+                    pw.println("attention check cache:");
+                    for (int i = 0; i < mAttentionCheckCacheBuffer.mSize; i++) {
+                        pw.increaseIndent();
+                        pw.println("timestamp=" + mAttentionCheckCacheBuffer.get(i).mTimestamp);
+                        pw.println("result=" + mAttentionCheckCacheBuffer.get(i).mResult);
+                        pw.decreaseIndent();
+                    }
                 }
             }
         }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index a6ac17d..6355af6 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -580,7 +580,8 @@
     }
 
     final private IUidObserver mUidObserver = new IUidObserver.Stub() {
-        @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
+        @Override public void onUidStateChanged(int uid, int procState, long procStateSeq,
+            int capability) {
         }
 
         @Override public void onUidGone(int uid, boolean disabled) {
@@ -1018,7 +1019,14 @@
 
         synchronized (mAudioPolicies) {
             for (AudioPolicyProxy policy : mAudioPolicies.values()) {
-                policy.connectMixes();
+                final int status = policy.connectMixes();
+                if (status != AudioSystem.SUCCESS) {
+                    // note that PERMISSION_DENIED may also indicate trouble getting to APService
+                    Log.e(TAG, "onAudioServerDied: error "
+                            + AudioSystem.audioSystemErrorToString(status)
+                            + " when connecting mixes for policy " + policy.toLogFriendlyString());
+                    policy.release();
+                }
             }
         }
 
@@ -1575,12 +1583,13 @@
         setMicrophoneMuteNoCallerCheck(currentUser);
     }
 
-    private int rescaleIndex(int index, int srcStream, int dstStream) {
-        int srcRange =
-                mStreamStates[srcStream].getMaxIndex() - mStreamStates[srcStream].getMinIndex();
-        int dstRange =
-                mStreamStates[dstStream].getMaxIndex() - mStreamStates[dstStream].getMinIndex();
+    private int getIndexRange(int streamType) {
+        return (mStreamStates[streamType].getMaxIndex() - mStreamStates[streamType].getMinIndex());
+    }
 
+    private int rescaleIndex(int index, int srcStream, int dstStream) {
+        int srcRange = getIndexRange(srcStream);
+        int dstRange = getIndexRange(dstStream);
         if (srcRange == 0) {
             Log.e(TAG, "rescaleIndex : index range should not be zero");
             return mStreamStates[dstStream].getMinIndex();
@@ -1591,6 +1600,17 @@
                 / srcRange;
     }
 
+    private int rescaleStep(int step, int srcStream, int dstStream) {
+        int srcRange = getIndexRange(srcStream);
+        int dstRange = getIndexRange(dstStream);
+        if (srcRange == 0) {
+            Log.e(TAG, "rescaleStep : index range should not be zero");
+            return 0;
+        }
+
+        return ((step * dstRange + srcRange / 2) / srcRange);
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // IPC methods
     ///////////////////////////////////////////////////////////////////////////
@@ -1767,7 +1787,7 @@
             }
         } else {
             // convert one UI step (+/-1) into a number of internal units on the stream alias
-            step = rescaleIndex(10, streamType, streamTypeAlias);
+            step = rescaleStep(10, streamType, streamTypeAlias);
         }
 
         // If either the client forces allowing ringer modes for this adjustment,
@@ -2777,6 +2797,7 @@
     }
 
     public void setMasterMute(boolean mute, int flags, String callingPackage, int userId) {
+        enforceModifyAudioRoutingPermission();
         setMasterMuteInternal(mute, flags, callingPackage, Binder.getCallingUid(),
                 userId);
     }
@@ -7019,16 +7040,8 @@
         }
 
         public void binderDied() {
-            synchronized (mAudioPolicies) {
-                Log.i(TAG, "audio policy " + mPolicyCallback + " died");
-                release();
-                mAudioPolicies.remove(mPolicyCallback.asBinder());
-            }
-            if (mIsVolumeController) {
-                synchronized (mExtVolumeControllerLock) {
-                    mExtVolumeController = null;
-                }
-            }
+            Log.i(TAG, "audio policy " + mPolicyCallback + " died");
+            release();
         }
 
         String getRegistrationId() {
@@ -7052,9 +7065,20 @@
                     Log.e(TAG, "Fail to unregister Audiopolicy callback from MediaProjection");
                 }
             }
+            if (mIsVolumeController) {
+                synchronized (mExtVolumeControllerLock) {
+                    mExtVolumeController = null;
+                }
+            }
             final long identity = Binder.clearCallingIdentity();
             AudioSystem.registerPolicyMixes(mMixes, false);
             Binder.restoreCallingIdentity(identity);
+            synchronized (mAudioPolicies) {
+                mAudioPolicies.remove(mPolicyCallback.asBinder());
+            }
+            try {
+                mPolicyCallback.notifyUnregistration();
+            } catch (RemoteException e) { }
         }
 
         boolean hasMixAffectingUsage(int usage, int excludedFlags) {
@@ -7105,7 +7129,7 @@
             }
         }
 
-        int connectMixes() {
+        @AudioSystem.AudioSystemError int connectMixes() {
             final long identity = Binder.clearCallingIdentity();
             int status = AudioSystem.registerPolicyMixes(mMixes, true);
             Binder.restoreCallingIdentity(identity);
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/services/core/java/com/android/server/backup/SystemBackupAgent.java
similarity index 100%
rename from core/java/com/android/server/backup/SystemBackupAgent.java
rename to services/core/java/com/android/server/backup/SystemBackupAgent.java
diff --git a/core/java/com/android/server/backup/UsageStatsBackupHelper.java b/services/core/java/com/android/server/backup/UsageStatsBackupHelper.java
similarity index 100%
rename from core/java/com/android/server/backup/UsageStatsBackupHelper.java
rename to services/core/java/com/android/server/backup/UsageStatsBackupHelper.java
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 619c21e..44c81fc 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -988,18 +988,6 @@
         }
     }
 
-    private String getErrorString(int modality, int error, int vendorCode) {
-        for (AuthenticatorWrapper authenticator : mAuthenticators) {
-            if (authenticator.modality == modality) {
-                // TODO(b/141025588): Refactor IBiometricServiceReceiver.aidl#onError(...) to not
-                // ask for a String error message, but derive it from the error code instead.
-                return "";
-            }
-        }
-        Slog.w(TAG, "Unable to get error string for modality: " + modality);
-        return null;
-    }
-
     private void logDialogDismissed(int reason) {
         if (reason == BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED) {
             // Explicit auth, authentication confirmed.
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index bc5973d..8762435 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -20,6 +20,7 @@
 import android.compat.annotation.EnabledAfter;
 import android.content.pm.ApplicationInfo;
 
+import com.android.internal.compat.CompatibilityChangeInfo;
 import com.android.server.compat.config.Change;
 
 import java.util.HashMap;
@@ -35,12 +36,8 @@
  *
  * <p>Note, this class is not thread safe so callers must ensure thread safety.
  */
-public final class CompatChange {
+public final class CompatChange extends CompatibilityChangeInfo {
 
-    private final long mChangeId;
-    @Nullable private final String mName;
-    private final int mEnableAfterTargetSdk;
-    private final boolean mDisabled;
     private Map<String, Boolean> mPackageOverrides;
 
     public CompatChange(long changeId) {
@@ -56,29 +53,15 @@
      */
     public CompatChange(long changeId, @Nullable String name, int enableAfterTargetSdk,
             boolean disabled) {
-        mChangeId = changeId;
-        mName = name;
-        mEnableAfterTargetSdk = enableAfterTargetSdk;
-        mDisabled = disabled;
+        super(changeId, name, enableAfterTargetSdk, disabled);
     }
 
     /**
      * @param change an object generated by services/core/xsd/platform-compat-config.xsd
      */
     public CompatChange(Change change) {
-        mChangeId = change.getId();
-        mName = change.getName();
-        mEnableAfterTargetSdk = change.getEnableAfterTargetSdk();
-        mDisabled = change.getDisabled();
-    }
-
-    long getId() {
-        return mChangeId;
-    }
-
-    @Nullable
-    String getName() {
-        return mName;
+        super(change.getId(), change.getName(), change.getEnableAfterTargetSdk(),
+                change.getDisabled());
     }
 
     /**
@@ -121,11 +104,11 @@
         if (mPackageOverrides != null && mPackageOverrides.containsKey(app.packageName)) {
             return mPackageOverrides.get(app.packageName);
         }
-        if (mDisabled) {
+        if (getDisabled()) {
             return false;
         }
-        if (mEnableAfterTargetSdk != -1) {
-            return app.targetSdkVersion > mEnableAfterTargetSdk;
+        if (getEnableAfterTargetSdk() != -1) {
+            return app.targetSdkVersion > getEnableAfterTargetSdk();
         }
         return true;
     }
@@ -133,14 +116,14 @@
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder("ChangeId(")
-                .append(mChangeId);
-        if (mName != null) {
-            sb.append("; name=").append(mName);
+                .append(getId());
+        if (getName() != null) {
+            sb.append("; name=").append(getName());
         }
-        if (mEnableAfterTargetSdk != -1) {
-            sb.append("; enableAfterTargetSdk=").append(mEnableAfterTargetSdk);
+        if (getEnableAfterTargetSdk() != -1) {
+            sb.append("; enableAfterTargetSdk=").append(getEnableAfterTargetSdk());
         }
-        if (mDisabled) {
+        if (getDisabled()) {
             sb.append("; disabled");
         }
         if (mPackageOverrides != null && mPackageOverrides.size() > 0) {
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 0fabd9a..d6ec22b 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -16,6 +16,7 @@
 
 package com.android.server.compat;
 
+import android.compat.Compatibility.ChangeConfig;
 import android.content.pm.ApplicationInfo;
 import android.os.Environment;
 import android.text.TextUtils;
@@ -26,6 +27,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.compat.CompatibilityChangeConfig;
+import com.android.internal.compat.CompatibilityChangeInfo;
 import com.android.server.compat.config.Change;
 import com.android.server.compat.config.XmlParser;
 
@@ -37,6 +39,8 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.Set;
 
 import javax.xml.datatype.DatatypeConfigurationException;
 /**
@@ -243,6 +247,49 @@
         }
     }
 
+    /**
+     * Get the config for a given app.
+     *
+     * @param applicationInfo the {@link ApplicationInfo} for which the info should be dumped.
+     * @return A {@link CompatibilityChangeConfig} which contains the compat config info for the
+     *         given app.
+     */
+
+    public CompatibilityChangeConfig getAppConfig(ApplicationInfo applicationInfo) {
+        Set<Long> enabled = new HashSet<>();
+        Set<Long> disabled = new HashSet<>();
+        synchronized (mChanges) {
+            for (int i = 0; i < mChanges.size(); ++i) {
+                CompatChange c = mChanges.valueAt(i);
+                if (c.isEnabled(applicationInfo)) {
+                    enabled.add(c.getId());
+                } else {
+                    disabled.add(c.getId());
+                }
+            }
+        }
+        return new CompatibilityChangeConfig(new ChangeConfig(enabled, disabled));
+    }
+
+    /**
+     * Dumps all the compatibility change information.
+     *
+     * @return An array of {@link CompatibilityChangeInfo} with the current changes.
+     */
+    public CompatibilityChangeInfo[] dumpChanges() {
+        synchronized (mChanges) {
+            CompatibilityChangeInfo[] changeInfos = new CompatibilityChangeInfo[mChanges.size()];
+            for (int i = 0; i < mChanges.size(); ++i) {
+                CompatChange change = mChanges.valueAt(i);
+                changeInfos[i] = new CompatibilityChangeInfo(change.getId(),
+                                                      change.getName(),
+                                                      change.getEnableAfterTargetSdk(),
+                                                      change.getDisabled());
+            }
+            return changeInfos;
+        }
+    }
+
     CompatConfig initConfigFromLib(File libraryDir) {
         if (!libraryDir.exists() || !libraryDir.isDirectory()) {
             Slog.e(TAG, "No directory " + libraryDir + ", skipping");
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 854f16a..75e2d22 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -19,12 +19,13 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.os.Process;
+import android.os.UserHandle;
 import android.util.Slog;
 import android.util.StatsLog;
 
 import com.android.internal.compat.ChangeReporter;
 import com.android.internal.compat.CompatibilityChangeConfig;
+import com.android.internal.compat.CompatibilityChangeInfo;
 import com.android.internal.compat.IPlatformCompat;
 import com.android.internal.util.DumpUtils;
 
@@ -54,8 +55,8 @@
     }
 
     @Override
-    public void reportChangeByPackageName(long changeId, String packageName) {
-        ApplicationInfo appInfo = getApplicationInfo(packageName);
+    public void reportChangeByPackageName(long changeId, String packageName, int userId) {
+        ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
         if (appInfo == null) {
             return;
         }
@@ -80,8 +81,8 @@
     }
 
     @Override
-    public boolean isChangeEnabledByPackageName(long changeId, String packageName) {
-        ApplicationInfo appInfo = getApplicationInfo(packageName);
+    public boolean isChangeEnabledByPackageName(long changeId, String packageName, int userId) {
+        ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
         if (appInfo == null) {
             return true;
         }
@@ -96,7 +97,8 @@
         }
         boolean enabled = true;
         for (String packageName : packages) {
-            enabled = enabled && isChangeEnabledByPackageName(changeId, packageName);
+            enabled = enabled && isChangeEnabledByPackageName(changeId, packageName,
+                    UserHandle.getUserId(uid));
         }
         return enabled;
     }
@@ -113,6 +115,16 @@
     }
 
     @Override
+    public CompatibilityChangeConfig getAppConfig(ApplicationInfo appInfo) {
+        return CompatConfig.get().getAppConfig(appInfo);
+    }
+
+    @Override
+    public CompatibilityChangeInfo[] listAllChanges() {
+        return CompatConfig.get().dumpChanges();
+    }
+
+    @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return;
         CompatConfig.get().dumpConfig(pw);
@@ -127,10 +139,9 @@
         mChangeReporter.resetReportedChanges(appInfo.uid);
     }
 
-    private ApplicationInfo getApplicationInfo(String packageName) {
+    private ApplicationInfo getApplicationInfo(String packageName, int userId) {
         try {
-            return mContext.getPackageManager().getApplicationInfoAsUser(packageName, 0,
-                    Process.myUid());
+            return mContext.getPackageManager().getApplicationInfoAsUser(packageName, 0, userId);
         } catch (PackageManager.NameNotFoundException e) {
             Slog.e(TAG, "No installed package " + packageName);
         }
diff --git a/services/core/java/com/android/server/compat/PlatformCompatNative.java b/services/core/java/com/android/server/compat/PlatformCompatNative.java
index 8399671..85dfbf4 100644
--- a/services/core/java/com/android/server/compat/PlatformCompatNative.java
+++ b/services/core/java/com/android/server/compat/PlatformCompatNative.java
@@ -29,8 +29,8 @@
     }
 
     @Override
-    public void reportChangeByPackageName(long changeId, String packageName) {
-        mPlatformCompat.reportChangeByPackageName(changeId, packageName);
+    public void reportChangeByPackageName(long changeId, String packageName, int userId) {
+        mPlatformCompat.reportChangeByPackageName(changeId, packageName, userId);
     }
 
     @Override
@@ -39,8 +39,8 @@
     }
 
     @Override
-    public boolean isChangeEnabledByPackageName(long changeId, String packageName) {
-        return mPlatformCompat.isChangeEnabledByPackageName(changeId, packageName);
+    public boolean isChangeEnabledByPackageName(long changeId, String packageName, int userId) {
+        return mPlatformCompat.isChangeEnabledByPackageName(changeId, packageName, userId);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 077c405..d13e675 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -53,7 +53,8 @@
         NO_INTERNET(SystemMessage.NOTE_NETWORK_NO_INTERNET),
         LOGGED_IN(SystemMessage.NOTE_NETWORK_LOGGED_IN),
         PARTIAL_CONNECTIVITY(SystemMessage.NOTE_NETWORK_PARTIAL_CONNECTIVITY),
-        SIGN_IN(SystemMessage.NOTE_NETWORK_SIGN_IN);
+        SIGN_IN(SystemMessage.NOTE_NETWORK_SIGN_IN),
+        PRIVATE_DNS_BROKEN(SystemMessage.NOTE_NETWORK_PRIVATE_DNS_BROKEN);
 
         public final int eventId;
 
@@ -175,13 +176,23 @@
         }
 
         Resources r = Resources.getSystem();
-        CharSequence title;
-        CharSequence details;
+        final CharSequence title;
+        final CharSequence details;
         int icon = getIcon(transportType, notifyType);
         if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
             title = r.getString(R.string.wifi_no_internet,
                     WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID()));
             details = r.getString(R.string.wifi_no_internet_detailed);
+        } else if (notifyType == NotificationType.PRIVATE_DNS_BROKEN) {
+            if (transportType == TRANSPORT_CELLULAR) {
+                title = r.getString(R.string.mobile_no_internet);
+            } else if (transportType == TRANSPORT_WIFI) {
+                title = r.getString(R.string.wifi_no_internet,
+                        WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID()));
+            } else {
+                title = r.getString(R.string.other_networks_no_internet);
+            }
+            details = r.getString(R.string.private_dns_broken_detailed);
         } else if (notifyType == NotificationType.PARTIAL_CONNECTIVITY
                 && transportType == TRANSPORT_WIFI) {
             title = r.getString(R.string.network_partial_connectivity,
@@ -357,8 +368,10 @@
         }
         switch (t) {
             case SIGN_IN:
-                return 5;
+                return 6;
             case PARTIAL_CONNECTIVITY:
+                return 5;
+            case PRIVATE_DNS_BROKEN:
                 return 4;
             case NO_INTERNET:
                 return 3;
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index e09c661..ebaa5a1 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -2032,13 +2032,17 @@
             int token;
             while ((token=in.readInt()) != STATUS_FILE_END) {
                 if (token == STATUS_FILE_ITEM) {
-                    SyncStatusInfo status = new SyncStatusInfo(in);
-                    if (mAuthorities.indexOfKey(status.authorityId) >= 0) {
-                        status.pending = false;
-                        if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
-                            Slog.v(TAG_FILE, "Adding status for id " + status.authorityId);
+                    try {
+                        SyncStatusInfo status = new SyncStatusInfo(in);
+                        if (mAuthorities.indexOfKey(status.authorityId) >= 0) {
+                            status.pending = false;
+                            if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+                                Slog.v(TAG_FILE, "Adding status for id " + status.authorityId);
+                            }
+                            mSyncStatus.put(status.authorityId, status);
                         }
-                        mSyncStatus.put(status.authorityId, status);
+                    } catch (Exception e) {
+                        Slog.e(TAG, "Unable to parse some sync status.", e);
                     }
                 } else {
                     // Ooops.
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index 0bf43b6..2dc2cf0 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -589,16 +589,18 @@
         if (immediate) {
             dtm.setColorMatrix(tintController.getLevel(), to);
         } else {
-            tintController.setAnimator(ValueAnimator.ofObject(COLOR_MATRIX_EVALUATOR,
-                    from == null ? MATRIX_IDENTITY : from, to));
-            tintController.getAnimator().setDuration(TRANSITION_DURATION);
-            tintController.getAnimator().setInterpolator(AnimationUtils.loadInterpolator(
+            TintValueAnimator valueAnimator = TintValueAnimator.ofMatrix(COLOR_MATRIX_EVALUATOR,
+                    from == null ? MATRIX_IDENTITY : from, to);
+            tintController.setAnimator(valueAnimator);
+            valueAnimator.setDuration(TRANSITION_DURATION);
+            valueAnimator.setInterpolator(AnimationUtils.loadInterpolator(
                     getContext(), android.R.interpolator.fast_out_slow_in));
-            tintController.getAnimator().addUpdateListener((ValueAnimator animator) -> {
+            valueAnimator.addUpdateListener((ValueAnimator animator) -> {
                 final float[] value = (float[]) animator.getAnimatedValue();
                 dtm.setColorMatrix(tintController.getLevel(), value);
+                ((TintValueAnimator) animator).updateMinMaxComponents();
             });
-            tintController.getAnimator().addListener(new AnimatorListenerAdapter() {
+            valueAnimator.addListener(new AnimatorListenerAdapter() {
 
                 private boolean mIsCancelled;
 
@@ -609,9 +611,14 @@
 
                 @Override
                 public void onAnimationEnd(Animator animator) {
+                    TintValueAnimator t = (TintValueAnimator) animator;
                     Slog.d(TAG, tintController.getClass().getSimpleName()
                             + " Animation cancelled: " + mIsCancelled
-                            + " to matrix: " + TintController.matrixToString(to, 16));
+                            + " to matrix: " + TintController.matrixToString(to, 16)
+                            + " min matrix coefficients: "
+                            + TintController.matrixToString(t.getMin(), 16)
+                            + " max matrix coefficients: "
+                            + TintController.matrixToString(t.getMax(), 16));
                     if (!mIsCancelled) {
                         // Ensure final color matrix is set at the end of the animation. If the
                         // animation is cancelled then don't set the final color matrix so the new
@@ -621,7 +628,7 @@
                     tintController.setAnimator(null);
                 }
             });
-            tintController.getAnimator().start();
+            valueAnimator.start();
         }
     }
 
@@ -1109,6 +1116,51 @@
     }
 
     /**
+     * Only animates matrices and saves min and max coefficients for logging.
+     */
+    static class TintValueAnimator extends ValueAnimator {
+        private float[] min;
+        private float[] max;
+
+        public static TintValueAnimator ofMatrix(ColorMatrixEvaluator evaluator,
+                Object... values) {
+            TintValueAnimator anim = new TintValueAnimator();
+            anim.setObjectValues(values);
+            anim.setEvaluator(evaluator);
+            if (values == null || values.length == 0) {
+                return null;
+            }
+            float[] m = (float[]) values[0];
+            anim.min = new float[m.length];
+            anim.max = new float[m.length];
+            for (int i = 0; i < m.length; ++i) {
+                anim.min[i] = Float.MAX_VALUE;
+                anim.max[i] = Float.MIN_VALUE;
+            }
+            return anim;
+        }
+
+        public void updateMinMaxComponents() {
+            float[] value = (float[]) getAnimatedValue();
+            if (value == null) {
+                return;
+            }
+            for (int i = 0; i < value.length; ++i) {
+                min[i] = Math.min(min[i], value[i]);
+                max[i] = Math.max(max[i], value[i]);
+            }
+        }
+
+        public float[] getMin() {
+            return min;
+        }
+
+        public float[] getMax() {
+            return max;
+        }
+    }
+
+    /**
      * Interpolates between two 4x4 color transform matrices (in column-major order).
      */
     private static class ColorMatrixEvaluator implements TypeEvaluator<float[]> {
diff --git a/services/core/java/com/android/server/display/color/DisplayTransformManager.java b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
index d5706a5..3b0069c 100644
--- a/services/core/java/com/android/server/display/color/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
@@ -111,6 +111,8 @@
     @GuardedBy("mDaltonizerModeLock")
     private int mDaltonizerMode = -1;
 
+    private static final IBinder sFlinger = ServiceManager.getService(SURFACE_FLINGER);
+
     /* package */ DisplayTransformManager() {
     }
 
@@ -195,25 +197,22 @@
      * Propagates the provided color transformation matrix to the SurfaceFlinger.
      */
     private static void applyColorMatrix(float[] m) {
-        final IBinder flinger = ServiceManager.getService(SURFACE_FLINGER);
-        if (flinger != null) {
-            final Parcel data = Parcel.obtain();
-            data.writeInterfaceToken("android.ui.ISurfaceComposer");
-            if (m != null) {
-                data.writeInt(1);
-                for (int i = 0; i < 16; i++) {
-                    data.writeFloat(m[i]);
-                }
-            } else {
-                data.writeInt(0);
+        final Parcel data = Parcel.obtain();
+        data.writeInterfaceToken("android.ui.ISurfaceComposer");
+        if (m != null) {
+            data.writeInt(1);
+            for (int i = 0; i < 16; i++) {
+                data.writeFloat(m[i]);
             }
-            try {
-                flinger.transact(SURFACE_FLINGER_TRANSACTION_COLOR_MATRIX, data, null, 0);
-            } catch (RemoteException ex) {
-                Slog.e(TAG, "Failed to set color transform", ex);
-            } finally {
-                data.recycle();
-            }
+        } else {
+            data.writeInt(0);
+        }
+        try {
+            sFlinger.transact(SURFACE_FLINGER_TRANSACTION_COLOR_MATRIX, data, null, 0);
+        } catch (RemoteException ex) {
+            Slog.e(TAG, "Failed to set color transform", ex);
+        } finally {
+            data.recycle();
         }
     }
 
@@ -221,18 +220,15 @@
      * Propagates the provided Daltonization mode to the SurfaceFlinger.
      */
     private static void applyDaltonizerMode(int mode) {
-        final IBinder flinger = ServiceManager.getService(SURFACE_FLINGER);
-        if (flinger != null) {
-            final Parcel data = Parcel.obtain();
-            data.writeInterfaceToken("android.ui.ISurfaceComposer");
-            data.writeInt(mode);
-            try {
-                flinger.transact(SURFACE_FLINGER_TRANSACTION_DALTONIZER, data, null, 0);
-            } catch (RemoteException ex) {
-                Slog.e(TAG, "Failed to set Daltonizer mode", ex);
-            } finally {
-                data.recycle();
-            }
+        final Parcel data = Parcel.obtain();
+        data.writeInterfaceToken("android.ui.ISurfaceComposer");
+        data.writeInt(mode);
+        try {
+            sFlinger.transact(SURFACE_FLINGER_TRANSACTION_DALTONIZER, data, null, 0);
+        } catch (RemoteException ex) {
+            Slog.e(TAG, "Failed to set Daltonizer mode", ex);
+        } finally {
+            data.recycle();
         }
     }
 
@@ -286,20 +282,17 @@
      * #SURFACE_FLINGER_TRANSACTION_QUERY_COLOR_MANAGED}.
      */
     public boolean isDeviceColorManaged() {
-        final IBinder flinger = ServiceManager.getService(SURFACE_FLINGER);
-        if (flinger != null) {
-            final Parcel data = Parcel.obtain();
-            final Parcel reply = Parcel.obtain();
-            data.writeInterfaceToken("android.ui.ISurfaceComposer");
-            try {
-                flinger.transact(SURFACE_FLINGER_TRANSACTION_QUERY_COLOR_MANAGED, data, reply, 0);
-                return reply.readBoolean();
-            } catch (RemoteException ex) {
-                Slog.e(TAG, "Failed to query wide color support", ex);
-            } finally {
-                data.recycle();
-                reply.recycle();
-            }
+        final Parcel data = Parcel.obtain();
+        final Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken("android.ui.ISurfaceComposer");
+        try {
+            sFlinger.transact(SURFACE_FLINGER_TRANSACTION_QUERY_COLOR_MANAGED, data, reply, 0);
+            return reply.readBoolean();
+        } catch (RemoteException ex) {
+            Slog.e(TAG, "Failed to query wide color support", ex);
+        } finally {
+            data.recycle();
+            reply.recycle();
         }
         return false;
     }
@@ -309,18 +302,15 @@
      */
     private void applySaturation(float saturation) {
         SystemProperties.set(PERSISTENT_PROPERTY_SATURATION, Float.toString(saturation));
-        final IBinder flinger = ServiceManager.getService(SURFACE_FLINGER);
-        if (flinger != null) {
-            final Parcel data = Parcel.obtain();
-            data.writeInterfaceToken("android.ui.ISurfaceComposer");
-            data.writeFloat(saturation);
-            try {
-                flinger.transact(SURFACE_FLINGER_TRANSACTION_SATURATION, data, null, 0);
-            } catch (RemoteException ex) {
-                Slog.e(TAG, "Failed to set saturation", ex);
-            } finally {
-                data.recycle();
-            }
+        final Parcel data = Parcel.obtain();
+        data.writeInterfaceToken("android.ui.ISurfaceComposer");
+        data.writeFloat(saturation);
+        try {
+            sFlinger.transact(SURFACE_FLINGER_TRANSACTION_SATURATION, data, null, 0);
+        } catch (RemoteException ex) {
+            Slog.e(TAG, "Failed to set saturation", ex);
+        } finally {
+            data.recycle();
         }
     }
 
@@ -334,21 +324,18 @@
                 Integer.toString(compositionColorMode));
         }
 
-        final IBinder flinger = ServiceManager.getService(SURFACE_FLINGER);
-        if (flinger != null) {
-            final Parcel data = Parcel.obtain();
-            data.writeInterfaceToken("android.ui.ISurfaceComposer");
-            data.writeInt(color);
-            if (compositionColorMode != Display.COLOR_MODE_INVALID) {
-                data.writeInt(compositionColorMode);
-            }
-            try {
-                flinger.transact(SURFACE_FLINGER_TRANSACTION_DISPLAY_COLOR, data, null, 0);
-            } catch (RemoteException ex) {
-                Slog.e(TAG, "Failed to set display color", ex);
-            } finally {
-                data.recycle();
-            }
+        final Parcel data = Parcel.obtain();
+        data.writeInterfaceToken("android.ui.ISurfaceComposer");
+        data.writeInt(color);
+        if (compositionColorMode != Display.COLOR_MODE_INVALID) {
+            data.writeInt(compositionColorMode);
+        }
+        try {
+            sFlinger.transact(SURFACE_FLINGER_TRANSACTION_DISPLAY_COLOR, data, null, 0);
+        } catch (RemoteException ex) {
+            Slog.e(TAG, "Failed to set display color", ex);
+        } finally {
+            data.recycle();
         }
     }
 
diff --git a/services/core/java/com/android/server/display/color/TintController.java b/services/core/java/com/android/server/display/color/TintController.java
index 8d8b9b2..422dd32 100644
--- a/services/core/java/com/android/server/display/color/TintController.java
+++ b/services/core/java/com/android/server/display/color/TintController.java
@@ -24,14 +24,14 @@
 
 abstract class TintController {
 
-    private ValueAnimator mAnimator;
+    private ColorDisplayService.TintValueAnimator mAnimator;
     private Boolean mIsActivated;
 
-    public ValueAnimator getAnimator() {
+    public ColorDisplayService.TintValueAnimator getAnimator() {
         return mAnimator;
     }
 
-    public void setAnimator(ValueAnimator animator) {
+    public void setAnimator(ColorDisplayService.TintValueAnimator animator) {
         mAnimator = animator;
     }
 
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 362955d..67a23dd 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -496,8 +496,6 @@
         }
 
         InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
-        // Give the output channel a token just for identity purposes.
-        inputChannels[0].setToken(new Binder());
         nativeRegisterInputMonitor(mPtr, inputChannels[0], displayId, false /*isGestureMonitor*/);
         inputChannels[0].dispose(); // don't need to retain the Java object reference
         return inputChannels[1];
@@ -528,7 +526,6 @@
         try {
             InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
             InputMonitorHost host = new InputMonitorHost(inputChannels[0]);
-            inputChannels[0].setToken(host.asBinder());
             nativeRegisterInputMonitor(mPtr, inputChannels[0], displayId,
                     true /*isGestureMonitor*/);
             return new InputMonitor(inputChannels[1], host);
@@ -547,7 +544,6 @@
         if (inputChannel == null) {
             throw new IllegalArgumentException("inputChannel must not be null.");
         }
-        inputChannel.setToken(new Binder());
 
         nativeRegisterInputChannel(mPtr, inputChannel);
     }
@@ -1810,8 +1806,9 @@
     }
 
     // Native callback.
-    private long notifyANR(IBinder token, String reason) {
-        return mWindowManagerCallbacks.notifyANR(
+    private long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
+            String reason) {
+        return mWindowManagerCallbacks.notifyANR(inputApplicationHandle,
                 token, reason);
     }
 
@@ -2055,7 +2052,12 @@
 
         public void notifyInputChannelBroken(IBinder token);
 
-        public long notifyANR(IBinder token, String reason);
+        /**
+         * Notifies the window manager about an application that is not responding.
+         * Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch.
+         */
+        long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
+                String reason);
 
         public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
 
@@ -2182,7 +2184,7 @@
 
         @Override
         public void pilferPointers() {
-            nativePilferPointers(mPtr, asBinder());
+            nativePilferPointers(mPtr, mInputChannel.getToken());
         }
 
         @Override
diff --git a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
new file mode 100644
index 0000000..c1567bc
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
@@ -0,0 +1,37 @@
+/*
+ * 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.server.integrity.parser;
+
+import com.android.server.integrity.model.Rule;
+
+import java.io.InputStream;
+
+/** A helper class to parse rules into the {@link Rule} model from Binary representation. */
+public class RuleBinaryParser implements RuleParser {
+
+    @Override
+    public Rule parse(String ruleText) {
+        // TODO: Implement binary text parser.
+        return null;
+    }
+
+    @Override
+    public Rule parse(InputStream inputStream) {
+        // TODO: Implement stream parser.
+        return null;
+    }
+}
diff --git a/services/core/java/com/android/server/integrity/parser/RuleParser.java b/services/core/java/com/android/server/integrity/parser/RuleParser.java
new file mode 100644
index 0000000..96ed5993
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/parser/RuleParser.java
@@ -0,0 +1,31 @@
+/*
+ * 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.server.integrity.parser;
+
+import com.android.server.integrity.model.Rule;
+
+import java.io.InputStream;
+
+/** A helper class to parse rules into the {@link Rule} model. */
+public interface RuleParser {
+
+    /** Parse rules from a string. */
+    Rule parse(String ruleText);
+
+    /** Parse rules from an input stream. */
+    Rule parse(InputStream inputStream);
+}
diff --git a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java
new file mode 100644
index 0000000..8b1bec9
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java
@@ -0,0 +1,37 @@
+/*
+ * 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.server.integrity.parser;
+
+import com.android.server.integrity.model.Rule;
+
+import java.io.InputStream;
+
+/** A helper class to parse rules into the {@link Rule} model from Xml representation. */
+public final class RuleXmlParser implements RuleParser {
+
+    @Override
+    public Rule parse(String ruleText) {
+        // TODO: Implement text parser.
+        return null;
+    }
+
+    @Override
+    public Rule parse(InputStream inputStream) {
+        // TODO: Implement stream parser.
+        return null;
+    }
+}
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
new file mode 100644
index 0000000..ecb00a4
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
@@ -0,0 +1,36 @@
+/*
+ * 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.server.integrity.serializer;
+
+import com.android.server.integrity.model.Rule;
+
+import java.io.OutputStream;
+
+/** A helper class to serialize rules from the {@link Rule} model to Xml representation. */
+public class RuleBinarySerializer implements RuleSerializer {
+
+    @Override
+    public void serialize(Rule rule, OutputStream outputStream) {
+        // TODO: Implement stream serializer.
+    }
+
+    @Override
+    public String serialize(Rule rule) {
+        // TODO: Implement text serializer.
+        return null;
+    }
+}
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java
new file mode 100644
index 0000000..07a912f
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java
@@ -0,0 +1,31 @@
+/*
+ * 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.server.integrity.serializer;
+
+import com.android.server.integrity.model.Rule;
+
+import java.io.OutputStream;
+
+/** A helper class to serialize rules from the {@link Rule} model. */
+public interface RuleSerializer {
+
+    /** Serialize a rule to an output stream */
+    void serialize(Rule rule, OutputStream outputStream);
+
+    /** Serialize a rule to a string. */
+    String serialize(Rule rule);
+}
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
new file mode 100644
index 0000000..62973e2
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
@@ -0,0 +1,36 @@
+/*
+ * 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.server.integrity.serializer;
+
+import com.android.server.integrity.model.Rule;
+
+import java.io.OutputStream;
+
+/** A helper class to serialize rules from the {@link Rule} model to Xml representation. */
+public class RuleXmlSerializer implements RuleSerializer {
+
+    @Override
+    public void serialize(Rule rule, OutputStream outputStream) {
+        // TODO: Implement stream serializer.
+    }
+
+    @Override
+    public String serialize(Rule rule) {
+        // TODO: Implement text serializer.
+        return null;
+    }
+}
diff --git a/services/core/java/com/android/server/location/CallerIdentity.java b/services/core/java/com/android/server/location/CallerIdentity.java
index 61e5d1f..75ba5b8 100644
--- a/services/core/java/com/android/server/location/CallerIdentity.java
+++ b/services/core/java/com/android/server/location/CallerIdentity.java
@@ -17,6 +17,7 @@
 package com.android.server.location;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 
 /**
  * Represents the calling process's uid, pid, and package name.
@@ -25,13 +26,15 @@
     public final int mUid;
     public final int mPid;
     public final String mPackageName;
+    public final @Nullable String mFeatureId;
     public final @NonNull String mListenerIdentifier;
 
-    public CallerIdentity(int uid, int pid, String packageName,
+    public CallerIdentity(int uid, int pid, String packageName, @Nullable String featureId,
             @NonNull String listenerIdentifier) {
         mUid = uid;
         mPid = pid;
         mPackageName = packageName;
+        mFeatureId = featureId;
         mListenerIdentifier = listenerIdentifier;
     }
 }
diff --git a/services/core/java/com/android/server/location/GeocoderProxy.java b/services/core/java/com/android/server/location/GeocoderProxy.java
index d9602b8..e6f0ed9 100644
--- a/services/core/java/com/android/server/location/GeocoderProxy.java
+++ b/services/core/java/com/android/server/location/GeocoderProxy.java
@@ -21,7 +21,7 @@
 import android.location.GeocoderParams;
 import android.location.IGeocodeProvider;
 
-import com.android.server.FgThread;
+import com.android.internal.os.BackgroundThread;
 import com.android.server.ServiceWatcher;
 
 import java.util.List;
@@ -53,7 +53,7 @@
             int initialPackageNamesResId) {
         mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, overlaySwitchResId,
                 defaultServicePackageNameResId, initialPackageNamesResId,
-                FgThread.getHandler());
+                BackgroundThread.getHandler());
     }
 
     private boolean bind() {
diff --git a/services/core/java/com/android/server/location/GeofenceManager.java b/services/core/java/com/android/server/location/GeofenceManager.java
index 4f10a71..17a2169 100644
--- a/services/core/java/com/android/server/location/GeofenceManager.java
+++ b/services/core/java/com/android/server/location/GeofenceManager.java
@@ -17,6 +17,7 @@
 package com.android.server.location;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
 import android.content.ContentResolver;
@@ -152,7 +153,7 @@
     }
 
     public void addFence(LocationRequest request, Geofence geofence, PendingIntent intent,
-            int allowedResolutionLevel, int uid, String packageName,
+            int allowedResolutionLevel, int uid, String packageName, @Nullable String featureId,
             @NonNull String listenerIdentifier) {
         if (D) {
             Slog.d(TAG, "addFence: request=" + request + ", geofence=" + geofence
@@ -160,8 +161,8 @@
         }
 
         GeofenceState state = new GeofenceState(geofence,
-                request.getExpireAt(), allowedResolutionLevel, uid, packageName, listenerIdentifier,
-                intent);
+                request.getExpireAt(), allowedResolutionLevel, uid, packageName, featureId,
+                listenerIdentifier, intent);
         synchronized (mLock) {
             // first make sure it doesn't already exist
             for (int i = mFences.size() - 1; i >= 0; i--) {
@@ -304,7 +305,7 @@
                 int op = LocationManagerService.resolutionLevelToOp(state.mAllowedResolutionLevel);
                 if (op >= 0) {
                     if (mAppOps.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, state.mUid,
-                            state.mPackageName, null, state.mListenerIdentifier)
+                            state.mPackageName, state.mFeatureId, state.mListenerIdentifier)
                             != AppOpsManager.MODE_ALLOWED) {
                         if (D) {
                             Slog.d(TAG, "skipping geofence processing for no op app: "
diff --git a/services/core/java/com/android/server/location/GeofenceState.java b/services/core/java/com/android/server/location/GeofenceState.java
index fe0719d..a91a1dc 100644
--- a/services/core/java/com/android/server/location/GeofenceState.java
+++ b/services/core/java/com/android/server/location/GeofenceState.java
@@ -18,6 +18,7 @@
 package com.android.server.location;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.PendingIntent;
 import android.location.Geofence;
 import android.location.Location;
@@ -39,6 +40,7 @@
     public final int mAllowedResolutionLevel;
     public final int mUid;
     public final String mPackageName;
+    public final @Nullable String mFeatureId;
     public final @NonNull String mListenerIdentifier;
     public final PendingIntent mIntent;
 
@@ -46,7 +48,8 @@
     double mDistanceToCenter;  // current distance to center of fence
 
     public GeofenceState(Geofence fence, long expireAt, int allowedResolutionLevel, int uid,
-            String packageName, @NonNull String listenerIdentifier, PendingIntent intent) {
+            String packageName, @Nullable String featureId, @NonNull String listenerIdentifier,
+            PendingIntent intent) {
         mState = STATE_UNKNOWN;
         mDistanceToCenter = Double.MAX_VALUE;
 
@@ -55,6 +58,7 @@
         mAllowedResolutionLevel = allowedResolutionLevel;
         mUid = uid;
         mPackageName = packageName;
+        mFeatureId = featureId;
         mListenerIdentifier = listenerIdentifier;
         mIntent = intent;
 
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 8bf01a3..fb57d69 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -67,6 +67,7 @@
 import android.util.TimeUtils;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.location.GpsNetInitiatedHandler;
 import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
@@ -304,6 +305,9 @@
     private final ExponentialBackOff mPsdsBackOff = new ExponentialBackOff(RETRY_INTERVAL,
             MAX_RETRY_INTERVAL);
 
+    private static boolean sIsInitialized = false;
+    private static boolean sStaticTestOverride = false;
+
     // True if we are enabled
     @GuardedBy("mLock")
     private boolean mGpsEnabled;
@@ -576,10 +580,26 @@
         }
     }
 
+    @VisibleForTesting
+    public static void setIsSupportedForTest(boolean override) {
+        sStaticTestOverride = override;
+    }
+
     public static boolean isSupported() {
+        if (sStaticTestOverride) {
+            return true;
+        }
+        ensureInitialized();
         return native_is_supported();
     }
 
+    private static synchronized void ensureInitialized() {
+        if (!sIsInitialized) {
+            class_init_native();
+        }
+        sIsInitialized = true;
+    }
+
     private void reloadGpsProperties() {
         mGnssConfiguration.reloadGpsProperties();
         setSuplHostPort();
@@ -598,6 +618,8 @@
             Looper looper) {
         super(context, locationProviderManager);
 
+        ensureInitialized();
+
         mLooper = looper;
 
         // Create a wake lock
@@ -814,7 +836,7 @@
 
         int elapsedRealtimeFlags = ELAPSED_REALTIME_HAS_TIMESTAMP_NS
                 | (location.hasElapsedRealtimeUncertaintyNanos()
-                        ? ELAPSED_REALTIME_HAS_TIME_UNCERTAINTY_NS : 0);
+                ? ELAPSED_REALTIME_HAS_TIME_UNCERTAINTY_NS : 0);
         long elapsedRealtimeNanos = location.getElapsedRealtimeNanos();
         double elapsedRealtimeUncertaintyNanos = location.getElapsedRealtimeUncertaintyNanos();
 
@@ -1005,7 +1027,7 @@
 
         // .. but enable anyway, if there's an active settings-ignored request (e.g. ELS)
         enabled |= (mProviderRequest != null && mProviderRequest.reportLocation
-                        && mProviderRequest.locationSettingsIgnored);
+                && mProviderRequest.locationSettingsIgnored);
 
         // ... and, finally, disable anyway, if device is being shut down
         enabled &= !mShutdown;
@@ -2224,10 +2246,6 @@
     // preallocated to avoid memory allocation in reportNmea()
     private byte[] mNmeaBuffer = new byte[120];
 
-    static {
-        class_init_native();
-    }
-
     private static native void class_init_native();
 
     private static native boolean native_is_supported();
diff --git a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
index ec05c31..55e427f 100644
--- a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
@@ -47,7 +47,7 @@
     }
 
     @VisibleForTesting
-    GnssMeasurementsProvider(
+    public GnssMeasurementsProvider(
             Context context, Handler handler, GnssMeasurementProviderNative aNative) {
         super(context, handler, TAG);
         mNative = aNative;
@@ -158,7 +158,7 @@
     }
 
     @VisibleForTesting
-    static class GnssMeasurementProviderNative {
+    public static class GnssMeasurementProviderNative {
         public boolean isMeasurementSupported() {
             return native_is_measurement_supported();
         }
diff --git a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
index 4c45ef6..983d1da 100644
--- a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
+++ b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
@@ -45,7 +45,7 @@
     }
 
     @VisibleForTesting
-    GnssNavigationMessageProvider(Context context, Handler handler,
+    public GnssNavigationMessageProvider(Context context, Handler handler,
             GnssNavigationMessageProviderNative aNative) {
         super(context, handler, TAG);
         mNative = aNative;
@@ -142,7 +142,7 @@
     }
 
     @VisibleForTesting
-    static class GnssNavigationMessageProviderNative {
+    public static class GnssNavigationMessageProviderNative {
         public boolean isNavigationMessageSupported() {
             return native_is_navigation_message_supported();
         }
diff --git a/services/core/java/com/android/server/location/RemoteListenerHelper.java b/services/core/java/com/android/server/location/RemoteListenerHelper.java
index 25b544f..60ce1f4 100644
--- a/services/core/java/com/android/server/location/RemoteListenerHelper.java
+++ b/services/core/java/com/android/server/location/RemoteListenerHelper.java
@@ -182,7 +182,7 @@
         }
 
         return mAppOps.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, callerIdentity.mUid,
-                callerIdentity.mPackageName, null,
+                callerIdentity.mPackageName, callerIdentity.mFeatureId,
                 "Location sent to " + callerIdentity.mListenerIdentifier)
                 == AppOpsManager.MODE_ALLOWED;
     }
diff --git a/services/core/java/com/android/server/location/TEST_MAPPING b/services/core/java/com/android/server/location/TEST_MAPPING
new file mode 100644
index 0000000..2e21fa6
--- /dev/null
+++ b/services/core/java/com/android/server/location/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsLocationCoarseTestCases"
+    },
+    {
+      "name": "CtsLocationNoneTestCases"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 9bbe628..d665001 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -1011,8 +1011,12 @@
     @Override
     public boolean getSeparateProfileChallengeEnabled(int userId) {
         checkReadPermission(SEPARATE_PROFILE_CHALLENGE_KEY, userId);
+        return getSeparateProfileChallengeEnabledInternal(userId);
+    }
+
+    private boolean getSeparateProfileChallengeEnabledInternal(int userId) {
         synchronized (mSeparateChallengeLock) {
-            return getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
+            return getBooleanUnchecked(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
         }
     }
 
@@ -1096,6 +1100,10 @@
     @Override
     public boolean getBoolean(String key, boolean defaultValue, int userId) {
         checkReadPermission(key, userId);
+        return getBooleanUnchecked(key, defaultValue, userId);
+    }
+
+    private boolean getBooleanUnchecked(String key, boolean defaultValue, int userId) {
         String value = getStringUnchecked(key, null, userId);
         return TextUtils.isEmpty(value) ?
                 defaultValue : (value.equals("1") || value.equals("true"));
@@ -3159,7 +3167,7 @@
             // observe it from the keyguard directly.
             pw.println("Quality: " + getKeyguardStoredQuality(userId));
             pw.println("CredentialType: " + getCredentialTypeInternal(userId));
-            pw.println("SeparateChallenge: " + getSeparateProfileChallengeEnabled(userId));
+            pw.println("SeparateChallenge: " + getSeparateProfileChallengeEnabledInternal(userId));
             pw.println(String.format("Metrics: %s",
                     getUserPasswordMetrics(userId) != null ? "known" : "unknown"));
             pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
index 71c7b23..0f8561e 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
@@ -16,14 +16,22 @@
 
 package com.android.server.locksettings;
 
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
+
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
+
 import android.app.ActivityManager;
+import android.app.admin.PasswordMetrics;
 import android.os.ShellCommand;
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
 import com.android.internal.widget.LockscreenCredential;
+import com.android.internal.widget.PasswordValidationError;
 
 import java.io.PrintWriter;
+import java.util.List;
 
 class LockSettingsShellCommand extends ShellCommand {
 
@@ -70,18 +78,19 @@
             if (!checkCredential()) {
                 return -1;
             }
+            boolean success = true;
             switch (cmd) {
                 case COMMAND_SET_PATTERN:
-                    runSetPattern();
+                    success = runSetPattern();
                     break;
                 case COMMAND_SET_PASSWORD:
-                    runSetPassword();
+                    success = runSetPassword();
                     break;
                 case COMMAND_SET_PIN:
-                    runSetPin();
+                    success = runSetPin();
                     break;
                 case COMMAND_CLEAR:
-                    runClear();
+                    success = runClear();
                     break;
                 case COMMAND_SP:
                     runChangeSp();
@@ -102,7 +111,7 @@
                     getErrPrintWriter().println("Unknown command: " + cmd);
                     break;
             }
-            return 0;
+            return success ? 0 : -1;
         } catch (Exception e) {
             getErrPrintWriter().println("Error while executing command: " + cmd);
             e.printStackTrace(getErrPrintWriter());
@@ -201,34 +210,66 @@
         }
     }
 
-    private void runSetPattern() {
-        mLockPatternUtils.setLockCredential(
-                LockscreenCredential.createPattern(LockPatternUtils.byteArrayToPattern(
-                        mNew.getBytes())),
-                getOldCredential(),
-                mCurrentUserId);
+    private boolean runSetPattern() {
+        final LockscreenCredential pattern = LockscreenCredential.createPattern(
+                LockPatternUtils.byteArrayToPattern(mNew.getBytes()));
+        if (!isNewCredentialSufficient(pattern)) {
+            return false;
+        }
+        mLockPatternUtils.setLockCredential(pattern, getOldCredential(), mCurrentUserId);
         getOutPrintWriter().println("Pattern set to '" + mNew + "'");
+        return true;
     }
 
-    private void runSetPassword() {
-        mLockPatternUtils.setLockCredential(LockscreenCredential.createPassword(mNew),
-                getOldCredential(),
-                mCurrentUserId);
+    private boolean runSetPassword() {
+        final LockscreenCredential password = LockscreenCredential.createPassword(mNew);
+        if (!isNewCredentialSufficient(password)) {
+            return false;
+        }
+        mLockPatternUtils.setLockCredential(password, getOldCredential(), mCurrentUserId);
         getOutPrintWriter().println("Password set to '" + mNew + "'");
+        return true;
     }
 
-    private void runSetPin() {
-        mLockPatternUtils.setLockCredential(LockscreenCredential.createPin(mNew),
-                getOldCredential(),
-                mCurrentUserId);
+    private boolean runSetPin() {
+        final LockscreenCredential pin = LockscreenCredential.createPin(mNew);
+        if (!isNewCredentialSufficient(pin)) {
+            return false;
+        }
+        mLockPatternUtils.setLockCredential(pin, getOldCredential(), mCurrentUserId);
         getOutPrintWriter().println("Pin set to '" + mNew + "'");
+        return true;
     }
 
-    private void runClear() {
-        mLockPatternUtils.setLockCredential(LockscreenCredential.createNone(),
-                getOldCredential(),
-                mCurrentUserId);
+    private boolean runClear() {
+        LockscreenCredential none = LockscreenCredential.createNone();
+        if (!isNewCredentialSufficient(none)) {
+            return false;
+        }
+        mLockPatternUtils.setLockCredential(none, getOldCredential(), mCurrentUserId);
         getOutPrintWriter().println("Lock credential cleared");
+        return true;
+    }
+
+    private boolean isNewCredentialSufficient(LockscreenCredential credential) {
+        final PasswordMetrics requiredMetrics =
+                mLockPatternUtils.getRequestedPasswordMetrics(mCurrentUserId);
+        final List<PasswordValidationError> errors;
+        if (credential.isPassword() || credential.isPin()) {
+            errors = PasswordMetrics.validatePassword(requiredMetrics, PASSWORD_COMPLEXITY_NONE,
+                    credential.isPin(), credential.getCredential());
+        } else {
+            PasswordMetrics metrics = new PasswordMetrics(
+                    credential.isPattern() ? CREDENTIAL_TYPE_PATTERN : CREDENTIAL_TYPE_NONE);
+            errors = PasswordMetrics.validatePasswordMetrics(
+                    requiredMetrics, PASSWORD_COMPLEXITY_NONE, false /* isPin */, metrics);
+        }
+        if (!errors.isEmpty()) {
+            getOutPrintWriter().println(
+                    "New credential doesn't satisfy admin policies: " + errors.get(0));
+            return false;
+        }
+        return true;
     }
 
     private void runSetDisabled() {
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
index 4816ceb..626bf1c 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
@@ -119,6 +119,11 @@
         }
     }
 
+    @NonNull
+    public String getUniqueId() {
+        return mUniqueId;
+    }
+
     @Nullable
     public MediaRoute2ProviderInfo getProviderInfo() {
         return mProviderInfo;
@@ -294,7 +299,7 @@
     }
 
     public interface Callback {
-        void onProviderStateChanged(MediaRoute2ProviderProxy provider);
+        void onProviderStateChanged(@NonNull MediaRoute2ProviderProxy provider);
     }
 
     private final class Connection implements DeathRecipient {
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 361dc36..44642d4 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -47,9 +47,12 @@
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * TODO: Merge this to MediaRouterService once it's finished.
@@ -357,8 +360,7 @@
             mAllClientRecords.put(binder, clientRecord);
 
             userRecord.mHandler.sendMessage(
-                    obtainMessage(UserHandler::notifyProviderInfosUpdatedToClient,
-                            userRecord.mHandler, client));
+                    obtainMessage(UserHandler::notifyRoutesToClient, userRecord.mHandler, client));
         }
     }
 
@@ -586,6 +588,7 @@
 
     final class UserRecord {
         public final int mUserId;
+        //TODO: make records private for thread-safety
         final ArrayList<ClientRecord> mClientRecords = new ArrayList<>();
         final ArrayList<ManagerRecord> mManagerRecords = new ArrayList<>();
         final UserHandler mHandler;
@@ -705,7 +708,7 @@
         //TODO: Make this thread-safe.
         private final ArrayList<MediaRoute2ProviderProxy> mMediaProviders =
                 new ArrayList<>();
-        private List<MediaRoute2ProviderInfo> mProviderInfos;
+        private final List<MediaRoute2ProviderInfo> mProviderInfos = new ArrayList<>();
 
         private boolean mRunning;
         private boolean mProviderInfosUpdateScheduled;
@@ -745,14 +748,89 @@
         }
 
         @Override
-        public void onProviderStateChanged(MediaRoute2ProviderProxy provider) {
-            updateProvider(provider);
+        public void onProviderStateChanged(@NonNull MediaRoute2ProviderProxy provider) {
+            sendMessage(PooledLambda.obtainMessage(UserHandler::updateProvider, this, provider));
         }
 
         private void updateProvider(MediaRoute2ProviderProxy provider) {
+            int providerIndex = getProviderInfoIndex(provider.getUniqueId());
+            MediaRoute2ProviderInfo providerInfo = provider.getProviderInfo();
+            MediaRoute2ProviderInfo prevInfo =
+                    (providerIndex < 0) ? null : mProviderInfos.get(providerIndex);
+
+            if (Objects.equals(prevInfo, providerInfo)) return;
+
+            if (prevInfo == null) {
+                mProviderInfos.add(providerInfo);
+                Collection<MediaRoute2Info> addedRoutes = providerInfo.getRoutes();
+                if (addedRoutes.size() > 0) {
+                    sendMessage(PooledLambda.obtainMessage(UserHandler::notifyRoutesAddedToClients,
+                            this, getClients(), new ArrayList<>(addedRoutes)));
+                }
+            } else if (providerInfo == null) {
+                mProviderInfos.remove(prevInfo);
+                Collection<MediaRoute2Info> removedRoutes = prevInfo.getRoutes();
+                if (removedRoutes.size() > 0) {
+                    sendMessage(PooledLambda.obtainMessage(
+                            UserHandler::notifyRoutesRemovedToClients,
+                            this, getClients(), new ArrayList<>(removedRoutes)));
+                }
+            } else {
+                mProviderInfos.set(providerIndex, providerInfo);
+                List<MediaRoute2Info> addedRoutes = new ArrayList<>();
+                List<MediaRoute2Info> removedRoutes = new ArrayList<>();
+                List<MediaRoute2Info> changedRoutes = new ArrayList<>();
+
+                final Collection<MediaRoute2Info> currentRoutes = providerInfo.getRoutes();
+                final Set<String> updatedRouteIds = new HashSet<>();
+
+                for (MediaRoute2Info route : currentRoutes) {
+                    if (!route.isValid()) {
+                        Slog.w(TAG, "Ignoring invalid route : " + route);
+                        continue;
+                    }
+                    MediaRoute2Info prevRoute = prevInfo.getRoute(route.getId());
+
+                    if (prevRoute != null) {
+                        if (!Objects.equals(prevRoute, route)) {
+                            changedRoutes.add(route);
+                        }
+                        updatedRouteIds.add(route.getId());
+                    } else {
+                        addedRoutes.add(route);
+                    }
+                }
+
+                for (MediaRoute2Info prevRoute : prevInfo.getRoutes()) {
+                    if (!updatedRouteIds.contains(prevRoute.getId())) {
+                        removedRoutes.add(prevRoute);
+                    }
+                }
+
+                List<IMediaRouter2Client> clients = getClients();
+                if (addedRoutes.size() > 0) {
+                    notifyRoutesAddedToClients(clients, addedRoutes);
+                }
+                if (removedRoutes.size() > 0) {
+                    notifyRoutesRemovedToClients(clients, removedRoutes);
+                }
+                if (changedRoutes.size() > 0) {
+                    notifyRoutesChangedToClients(clients, changedRoutes);
+                }
+            }
             scheduleUpdateProviderInfos();
         }
 
+        private int getProviderInfoIndex(String providerId) {
+            for (int i = 0; i < mProviderInfos.size(); i++) {
+                MediaRoute2ProviderInfo providerInfo = mProviderInfos.get(i);
+                if (TextUtils.equals(providerInfo.getUniqueId(), providerId)) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
         private void selectRoute(ClientRecord clientRecord, MediaRoute2Info route) {
             if (route != null) {
                 MediaRoute2ProviderProxy provider = findProvider(route.getProviderId());
@@ -803,6 +881,7 @@
             }
         }
 
+        //TODO: should be replaced into notifyRoutes...ToManagers
         private void updateProviderInfos() {
             mProviderInfosUpdateScheduled = false;
 
@@ -810,55 +889,83 @@
             if (service == null) {
                 return;
             }
-            final List<MediaRoute2ProviderInfo> providers = new ArrayList<>();
-            for (MediaRoute2ProviderProxy mediaProvider : mMediaProviders) {
-                final MediaRoute2ProviderInfo providerInfo =
-                        mediaProvider.getProviderInfo();
-                if (providerInfo == null || !providerInfo.isValid()) {
-                    Slog.w(TAG, "Ignoring invalid provider info : " + providerInfo);
-                } else {
-                    providers.add(providerInfo);
-                }
-            }
-            mProviderInfos = providers;
 
             final List<IMediaRouter2Manager> managers = new ArrayList<>();
-            final List<IMediaRouter2Client> clients = new ArrayList<>();
             synchronized (service.mLock) {
                 for (ManagerRecord managerRecord : mUserRecord.mManagerRecords) {
                     managers.add(managerRecord.mManager);
                 }
+            }
+            for (IMediaRouter2Manager manager : managers) {
+                notifyProviderInfosUpdatedToManager(manager);
+            }
+        }
+
+        private List<IMediaRouter2Client> getClients() {
+            final List<IMediaRouter2Client> clients = new ArrayList<>();
+            MediaRouter2ServiceImpl service = mServiceRef.get();
+            if (service == null) {
+                return clients;
+            }
+            synchronized (service.mLock) {
                 for (ClientRecord clientRecord : mUserRecord.mClientRecords) {
                     if (clientRecord instanceof Client2Record) {
                         clients.add(((Client2Record) clientRecord).mClient);
                     }
                 }
             }
-            for (IMediaRouter2Manager manager : managers) {
-                notifyProviderInfosUpdatedToManager(manager);
-            }
-            for (IMediaRouter2Client client : clients) {
-                notifyProviderInfosUpdatedToClient(client);
-            }
+            return clients;
         }
 
-        private void notifyProviderInfosUpdatedToClient(IMediaRouter2Client client) {
-            if (mProviderInfos == null) {
-                scheduleUpdateProviderInfos();
+        private void notifyRoutesToClient(IMediaRouter2Client client) {
+            List<MediaRoute2Info> routes = new ArrayList<>();
+            for (MediaRoute2ProviderInfo providerInfo : mProviderInfos) {
+                routes.addAll(providerInfo.getRoutes());
+            }
+            if (routes.size() == 0) {
                 return;
             }
             try {
-                client.notifyProviderInfosUpdated(mProviderInfos);
+                client.notifyRoutesAdded(routes);
             } catch (RemoteException ex) {
-                Slog.w(TAG, "Failed to notify provider infos updated. Client probably died.");
+                Slog.w(TAG, "Failed to notify all routes. Client probably died.", ex);
+            }
+        }
+
+        private void notifyRoutesAddedToClients(List<IMediaRouter2Client> clients,
+                List<MediaRoute2Info> routes) {
+            for (IMediaRouter2Client client : clients) {
+                try {
+                    client.notifyRoutesAdded(routes);
+                } catch (RemoteException ex) {
+                    Slog.w(TAG, "Failed to notify routes added. Client probably died.", ex);
+                }
+            }
+        }
+
+        private void notifyRoutesRemovedToClients(List<IMediaRouter2Client> clients,
+                List<MediaRoute2Info> routes) {
+            for (IMediaRouter2Client client : clients) {
+                try {
+                    client.notifyRoutesRemoved(routes);
+                } catch (RemoteException ex) {
+                    Slog.w(TAG, "Failed to notify routes removed. Client probably died.", ex);
+                }
+            }
+        }
+
+        private void notifyRoutesChangedToClients(List<IMediaRouter2Client> clients,
+                List<MediaRoute2Info> routes) {
+            for (IMediaRouter2Client client : clients) {
+                try {
+                    client.notifyRoutesChanged(routes);
+                } catch (RemoteException ex) {
+                    Slog.w(TAG, "Failed to notify routes changed. Client probably died.", ex);
+                }
             }
         }
 
         private void notifyProviderInfosUpdatedToManager(IMediaRouter2Manager manager) {
-            if (mProviderInfos == null) {
-                scheduleUpdateProviderInfos();
-                return;
-            }
             try {
                 manager.notifyProviderInfosUpdated(mProviderInfos);
             } catch (RemoteException ex) {
@@ -891,9 +998,7 @@
 
         private MediaRoute2ProviderProxy findProvider(String providerId) {
             for (MediaRoute2ProviderProxy provider : mMediaProviders) {
-                final MediaRoute2ProviderInfo providerInfo = provider.getProviderInfo();
-                if (providerInfo != null
-                        && TextUtils.equals(providerInfo.getUniqueId(), providerId)) {
+                if (TextUtils.equals(provider.getUniqueId(), providerId)) {
                     return provider;
                 }
             }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 09be474..32d4b72 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -229,6 +229,8 @@
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
 import com.android.server.SystemConfig;
+import com.android.server.usage.AppStandbyInternal;
+import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
 
 import libcore.io.IoUtils;
 
@@ -363,7 +365,7 @@
             "com.android.server.net.action.SNOOZE_RAPID";
 
     /**
-     * Indicates the maximum wait time for admin data to be available;
+     * Indicates the maximum wait time for admin data to be available.
      */
     private static final long WAIT_FOR_ADMIN_DATA_TIMEOUT_MS = 10_000;
 
@@ -396,6 +398,7 @@
     private NetworkStatsManagerInternal mNetworkStats;
     private final INetworkManagementService mNetworkManager;
     private UsageStatsManagerInternal mUsageStats;
+    private AppStandbyInternal mAppStandby;
     private final Clock mClock;
     private final UserManager mUserManager;
     private final CarrierConfigManager mCarrierConfigManager;
@@ -734,6 +737,7 @@
             }
 
             mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
+            mAppStandby = LocalServices.getService(AppStandbyInternal.class);
             mNetworkStats = LocalServices.getService(NetworkStatsManagerInternal.class);
 
             synchronized (mUidRulesFirstLock) {
@@ -868,7 +872,7 @@
             mContext.getSystemService(ConnectivityManager.class).registerNetworkCallback(
                     new NetworkRequest.Builder().build(), mNetworkCallback);
 
-            mUsageStats.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
+            mAppStandby.addListener(new NetPolicyAppIdleStateChangeListener());
 
             // Listen for subscriber changes
             mContext.getSystemService(SubscriptionManager.class).addOnSubscriptionsChangedListener(
@@ -908,7 +912,8 @@
     }
 
     final private IUidObserver mUidObserver = new IUidObserver.Stub() {
-        @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
+        @Override public void onUidStateChanged(int uid, int procState, long procStateSeq,
+                int capability) {
             mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED,
                     uid, procState, procStateSeq).sendToTarget();
         }
@@ -4375,9 +4380,7 @@
         return newUidRules;
     }
 
-    private class AppIdleStateChangeListener
-            extends UsageStatsManagerInternal.AppIdleStateChangeListener {
-
+    private class NetPolicyAppIdleStateChangeListener extends AppIdleStateChangeListener {
         @Override
         public void onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket,
                 int reason) {
diff --git a/services/core/java/com/android/server/net/TEST_MAPPING b/services/core/java/com/android/server/net/TEST_MAPPING
new file mode 100644
index 0000000..9f04260
--- /dev/null
+++ b/services/core/java/com/android/server/net/TEST_MAPPING
@@ -0,0 +1,31 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsHostsideNetworkTests",
+      "file_patterns": ["(/|^)NetworkPolicy[^/]*\\.java"],
+      "options": [
+        {
+          "include-filter": "com.android.cts.net.HostsideRestrictBackgroundNetworkTests"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "FrameworksServicesTests",
+      "file_patterns": ["(/|^)NetworkPolicy[^/]*\\.java"],
+      "options": [
+        {
+          "include-filter": "com.android.server.net."
+        },
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    }
+  ]
+}
diff --git a/services/core/java/com/android/server/notification/InlineReplyUriRecord.java b/services/core/java/com/android/server/notification/InlineReplyUriRecord.java
new file mode 100644
index 0000000..76cfb03
--- /dev/null
+++ b/services/core/java/com/android/server/notification/InlineReplyUriRecord.java
@@ -0,0 +1,97 @@
+/*
+ * 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.server.notification;
+
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.UserHandle;
+import android.util.ArraySet;
+
+/**
+ * A record of inline reply (ex. RemoteInput) URI grants associated with a Notification.
+ */
+public final class InlineReplyUriRecord {
+    private final IBinder mPermissionOwner;
+    private final ArraySet<Uri> mUris;
+    private final UserHandle mUser;
+    private final String mPackageName;
+    private final String mKey;
+
+    /**
+     * Construct a new InlineReplyUriRecord.
+     * @param owner The PermissionOwner associated with this record.
+     * @param user The user associated with this record.
+     * @param packageName The name of the package which posted the notification.
+     * @param key The key of the original NotificationRecord this notification as created with.
+     */
+    public InlineReplyUriRecord(IBinder owner, UserHandle user, String packageName, String key) {
+        mPermissionOwner = owner;
+        mUris = new ArraySet<>();
+        mUser = user;
+        mPackageName = packageName;
+        mKey = key;
+    }
+
+    /**
+     * Get the permission owner associated with this record.
+     */
+    public IBinder getPermissionOwner() {
+        return mPermissionOwner;
+    }
+
+    /**
+     * Get the content URIs associated with this record.
+     */
+    public ArraySet<Uri> getUris() {
+        return mUris;
+    }
+
+    /**
+     * Associate a new content URI with this record.
+     */
+    public void addUri(Uri uri) {
+        mUris.add(uri);
+    }
+
+    /**
+     * Get the user id associated with this record.
+     * If the UserHandle associated with this record belongs to USER_ALL, return the ID for
+     * USER_SYSTEM instead, to avoid errors around modifying URI permissions for an invalid user ID.
+     */
+    public int getUserId() {
+        int userId = mUser.getIdentifier();
+        if (userId == UserHandle.USER_ALL) {
+            return UserHandle.USER_SYSTEM;
+        } else {
+            return userId;
+        }
+    }
+
+    /**
+     * Get the name of the package associated with this record.
+     */
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    /**
+     * Get the key associated with this record.
+     */
+    public String getKey() {
+        return mKey;
+    }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java
index 6f0ad33..88fc072 100644
--- a/services/core/java/com/android/server/notification/NotificationDelegate.java
+++ b/services/core/java/com/android/server/notification/NotificationDelegate.java
@@ -18,6 +18,7 @@
 
 import android.app.Notification;
 import android.net.Uri;
+import android.os.UserHandle;
 import android.service.notification.NotificationStats;
 
 import com.android.internal.statusbar.NotificationVisibility;
@@ -53,7 +54,13 @@
      * Grant permission to read the specified URI to the package associated with the
      * NotificationRecord associated with the given key.
      */
-    void grantInlineReplyUriPermission(String key, Uri uri, int callingUid);
+    void grantInlineReplyUriPermission(String key, Uri uri, UserHandle user, String packageName,
+            int callingUid);
+
+    /**
+     * Clear inline URI grants associated with the given notification.
+     */
+    void clearInlineReplyUriPermissions(String key, int callingUid);
 
     /**
      * Notifies that smart replies and actions have been added to the UI.
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
new file mode 100644
index 0000000..99b1ef4
--- /dev/null
+++ b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
@@ -0,0 +1,300 @@
+/*
+ * 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.server.notification;
+
+import android.app.NotificationHistory;
+import android.app.NotificationHistory.HistoricalNotification;
+import android.os.Handler;
+import android.util.AtomicFile;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+/**
+ * Provides an interface to write and query for notification history data for a user from a Protocol
+ * Buffer database.
+ *
+ * Periodically writes the buffered history to disk but can also accept force writes based on
+ * outside changes (like a pending shutdown).
+ */
+public class NotificationHistoryDatabase {
+    private static final int DEFAULT_CURRENT_VERSION = 1;
+
+    private static final String TAG = "NotiHistoryDatabase";
+    private static final boolean DEBUG = NotificationManagerService.DBG;
+    private static final int HISTORY_RETENTION_DAYS = 2;
+    private static final long WRITE_BUFFER_INTERVAL_MS = 1000 * 60 * 20;
+
+    private final Object mLock = new Object();
+    private Handler mFileWriteHandler;
+    @VisibleForTesting
+    // List of files holding history information, sorted newest to oldest
+    final LinkedList<AtomicFile> mHistoryFiles;
+    private final GregorianCalendar mCal;
+    private final File mHistoryDir;
+    private final File mVersionFile;
+    // Current version of the database files schema
+    private int mCurrentVersion;
+    private final WriteBufferRunnable mWriteBufferRunnable;
+
+    // Object containing posted notifications that have not yet been written to disk
+    @VisibleForTesting
+    NotificationHistory mBuffer;
+
+    public NotificationHistoryDatabase(File dir) {
+        mCurrentVersion = DEFAULT_CURRENT_VERSION;
+        mVersionFile = new File(dir, "version");
+        mHistoryDir = new File(dir, "history");
+        mHistoryFiles = new LinkedList<>();
+        mCal = new GregorianCalendar();
+        mBuffer = new NotificationHistory();
+        mWriteBufferRunnable = new WriteBufferRunnable();
+    }
+
+    public void init(Handler fileWriteHandler) {
+        synchronized (mLock) {
+            mFileWriteHandler = fileWriteHandler;
+
+            try {
+                mHistoryDir.mkdir();
+                mVersionFile.createNewFile();
+            } catch (Exception e) {
+                Slog.e(TAG, "could not create needed files", e);
+            }
+
+            checkVersionAndBuildLocked();
+            indexFilesLocked();
+            prune(HISTORY_RETENTION_DAYS, System.currentTimeMillis());
+        }
+    }
+
+    private void indexFilesLocked() {
+        mHistoryFiles.clear();
+        final File[] files = mHistoryDir.listFiles();
+        if (files == null) {
+            return;
+        }
+
+        // Sort with newest files first
+        Arrays.sort(files, (lhs, rhs) -> Long.compare(rhs.lastModified(), lhs.lastModified()));
+
+        for (File file : files) {
+            mHistoryFiles.addLast(new AtomicFile(file));
+        }
+    }
+
+    private void checkVersionAndBuildLocked() {
+        int version;
+        try (BufferedReader reader = new BufferedReader(new FileReader(mVersionFile))) {
+            version = Integer.parseInt(reader.readLine());
+        } catch (NumberFormatException | IOException e) {
+            version = 0;
+        }
+
+        if (version != mCurrentVersion && mVersionFile.exists()) {
+            try (BufferedWriter writer = new BufferedWriter(new FileWriter(mVersionFile))) {
+                writer.write(Integer.toString(mCurrentVersion));
+                writer.write("\n");
+                writer.flush();
+            } catch (IOException e) {
+                Slog.e(TAG, "Failed to write new version");
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    void forceWriteToDisk() {
+        if (!mFileWriteHandler.hasCallbacks(mWriteBufferRunnable)) {
+            mFileWriteHandler.post(mWriteBufferRunnable);
+        }
+    }
+
+    void onPackageRemoved(String packageName) {
+        RemovePackageRunnable rpr = new RemovePackageRunnable(packageName);
+        mFileWriteHandler.post(rpr);
+    }
+
+    public void addNotification(final HistoricalNotification notification) {
+        synchronized (mLock) {
+            mBuffer.addNotificationToWrite(notification);
+            // Each time we have new history to write to disk, schedule a write in [interval] ms
+            if (mBuffer.getHistoryCount() == 1) {
+                mFileWriteHandler.postDelayed(mWriteBufferRunnable, WRITE_BUFFER_INTERVAL_MS);
+            }
+        }
+    }
+
+    public NotificationHistory readNotificationHistory() {
+        synchronized (mLock) {
+            NotificationHistory notifications = new NotificationHistory();
+
+            for (AtomicFile file : mHistoryFiles) {
+                try {
+                    readLocked(
+                            file, notifications, new NotificationHistoryFilter.Builder().build());
+                } catch (Exception e) {
+                    Slog.e(TAG, "error reading " + file.getBaseFile().getName(), e);
+                }
+            }
+
+            return notifications;
+        }
+    }
+
+    public NotificationHistory readNotificationHistory(String packageName, String channelId,
+            int maxNotifications) {
+        synchronized (mLock) {
+            NotificationHistory notifications = new NotificationHistory();
+
+            for (AtomicFile file : mHistoryFiles) {
+                try {
+                    readLocked(file, notifications,
+                            new NotificationHistoryFilter.Builder()
+                                    .setPackage(packageName)
+                                    .setChannel(packageName, channelId)
+                                    .setMaxNotifications(maxNotifications)
+                                    .build());
+                    if (maxNotifications == notifications.getHistoryCount()) {
+                        // No need to read any more files
+                        break;
+                    }
+                } catch (Exception e) {
+                    Slog.e(TAG, "error reading " + file.getBaseFile().getName(), e);
+                }
+            }
+
+            return notifications;
+        }
+    }
+
+    /**
+     * Remove any files that are too old.
+     */
+    public void prune(final int retentionDays, final long currentTimeMillis) {
+        synchronized (mLock) {
+            mCal.setTimeInMillis(currentTimeMillis);
+            mCal.add(Calendar.DATE, -1 * retentionDays);
+
+            while (!mHistoryFiles.isEmpty()) {
+                final AtomicFile currentOldestFile = mHistoryFiles.getLast();
+                final long age = currentTimeMillis
+                        - currentOldestFile.getBaseFile().lastModified();
+                if (age > mCal.getTimeInMillis()) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "Removed " + currentOldestFile.getBaseFile().getName());
+                    }
+                    currentOldestFile.delete();
+                    mHistoryFiles.removeLast();
+                } else {
+                    // all remaining files are newer than the cut off
+                    return;
+                }
+            }
+        }
+    }
+
+    private void writeLocked(AtomicFile file, NotificationHistory notifications)
+            throws IOException {
+        FileOutputStream fos = file.startWrite();
+        try {
+            NotificationHistoryProtoHelper.write(fos, notifications, mCurrentVersion);
+            file.finishWrite(fos);
+            fos = null;
+        } finally {
+            // When fos is null (successful write), this will no-op
+            file.failWrite(fos);
+        }
+    }
+
+    private static void readLocked(AtomicFile file, NotificationHistory notificationsOut,
+            NotificationHistoryFilter filter) throws IOException {
+        try (FileInputStream in = file.openRead()) {
+            NotificationHistoryProtoHelper.read(in, notificationsOut, filter);
+        } catch (FileNotFoundException e) {
+            Slog.e(TAG, "Cannot file " + file.getBaseFile().getName(), e);
+            throw e;
+        }
+    }
+
+    private final class WriteBufferRunnable implements Runnable {
+        @Override
+        public void run() {
+            if (DEBUG) Slog.d(TAG, "WriteBufferRunnable");
+            synchronized (mLock) {
+                final AtomicFile latestNotificationsFiles = new AtomicFile(
+                        new File(mHistoryDir, String.valueOf(System.currentTimeMillis())));
+                try {
+                    writeLocked(latestNotificationsFiles, mBuffer);
+                    mHistoryFiles.addFirst(latestNotificationsFiles);
+                    mBuffer = new NotificationHistory();
+                } catch (IOException e) {
+                    Slog.e(TAG, "Failed to write buffer to disk. not flushing buffer", e);
+                }
+            }
+        }
+    }
+
+    private final class RemovePackageRunnable implements Runnable {
+        private String mPkg;
+
+        public RemovePackageRunnable(String pkg) {
+            mPkg = pkg;
+        }
+
+        @Override
+        public void run() {
+            if (DEBUG) Slog.d(TAG, "RemovePackageRunnable");
+            synchronized (mLock) {
+                // Remove packageName entries from pending history
+                mBuffer.removeNotificationsFromWrite(mPkg);
+
+                // Remove packageName entries from files on disk, and rewrite them to disk
+                // Since we sort by modified date, we have to update the files oldest to newest to
+                // maintain the original ordering
+                Iterator<AtomicFile> historyFileItr = mHistoryFiles.descendingIterator();
+                while (historyFileItr.hasNext()) {
+                    final AtomicFile af = historyFileItr.next();
+                    try {
+                        final NotificationHistory notifications = new NotificationHistory();
+                        readLocked(af, notifications,
+                                new NotificationHistoryFilter.Builder().build());
+                        notifications.removeNotificationsFromWrite(mPkg);
+                        writeLocked(af, notifications);
+                    } catch (Exception e) {
+                        Slog.e(TAG, "Cannot clean up file on pkg removal "
+                                + af.getBaseFile().getName(), e);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryFilter.java b/services/core/java/com/android/server/notification/NotificationHistoryFilter.java
new file mode 100644
index 0000000..c3b2e73
--- /dev/null
+++ b/services/core/java/com/android/server/notification/NotificationHistoryFilter.java
@@ -0,0 +1,125 @@
+/*
+ * 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.server.notification;
+
+import android.annotation.NonNull;
+import android.app.NotificationHistory;
+import android.app.NotificationHistory.HistoricalNotification;
+import android.text.TextUtils;
+
+import com.android.internal.util.Preconditions;
+
+public final class NotificationHistoryFilter {
+    private String mPackage;
+    private String mChannel;
+    private int mNotificationCount;
+
+    private NotificationHistoryFilter() {}
+
+    public String getPackage() {
+        return mPackage;
+    }
+
+    public String getChannel() {
+        return mChannel;
+    }
+
+    public int getMaxNotifications() {
+        return mNotificationCount;
+    }
+
+    /**
+     * Returns whether any of the filtering conditions are set
+     */
+    public boolean isFiltering() {
+        return getPackage() != null || getChannel() != null
+                || mNotificationCount < Integer.MAX_VALUE;
+    }
+
+    /**
+     * Returns true if this notification passes the package and channel name filter, false
+     * otherwise.
+     */
+    public boolean matchesPackageAndChannelFilter(HistoricalNotification notification) {
+        if (!TextUtils.isEmpty(getPackage())) {
+            if (!getPackage().equals(notification.getPackage())) {
+                return false;
+            } else {
+                if (!TextUtils.isEmpty(getChannel())
+                        && !getChannel().equals(notification.getChannelId())) {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns true if the NotificationHistory can accept another notification.
+     */
+    public boolean matchesCountFilter(NotificationHistory notifications) {
+        return notifications.getHistoryCount() < mNotificationCount;
+    }
+
+    public static final class Builder {
+        private String mPackage = null;
+        private String mChannel = null;
+        private int mNotificationCount = Integer.MAX_VALUE;
+
+        /**
+         * Constructor
+         */
+        public Builder() {}
+
+        /**
+         * Sets a package name filter
+         */
+        public Builder setPackage(String aPackage) {
+            mPackage = aPackage;
+            return this;
+        }
+
+        /**
+         * Sets a channel name filter. Only valid if there is also a package name filter
+         */
+        public Builder setChannel(String pkg, String channel) {
+            setPackage(pkg);
+            mChannel = channel;
+            return this;
+        }
+
+        /**
+         * Sets the max historical notifications
+         */
+        public Builder setMaxNotifications(int notificationCount) {
+            mNotificationCount = notificationCount;
+            return this;
+        }
+
+        /**
+         * Makes a NotificationHistoryFilter
+         */
+        public NotificationHistoryFilter build() {
+            NotificationHistoryFilter filter = new NotificationHistoryFilter();
+            filter.mPackage = mPackage;
+            filter.mChannel = mChannel;
+            filter.mNotificationCount = mNotificationCount;
+            return filter;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryProtoHelper.java b/services/core/java/com/android/server/notification/NotificationHistoryProtoHelper.java
new file mode 100644
index 0000000..2831d37
--- /dev/null
+++ b/services/core/java/com/android/server/notification/NotificationHistoryProtoHelper.java
@@ -0,0 +1,321 @@
+/*
+ * 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.server.notification;
+
+import android.app.NotificationHistory;
+import android.app.NotificationHistory.HistoricalNotification;
+import android.content.res.Resources;
+import android.graphics.drawable.Icon;
+import android.util.Slog;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.notification.NotificationHistoryProto.Notification;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Notification history reader/writer for Protocol Buffer format
+ */
+final class NotificationHistoryProtoHelper {
+    private static final String TAG = "NotifHistoryProto";
+
+    // Static-only utility class.
+    private NotificationHistoryProtoHelper() {}
+
+    private static List<String> readStringPool(ProtoInputStream proto) throws IOException {
+        final long token = proto.start(NotificationHistoryProto.STRING_POOL);
+        List<String> stringPool;
+        if (proto.nextField(NotificationHistoryProto.StringPool.SIZE)) {
+            stringPool = new ArrayList(proto.readInt(NotificationHistoryProto.StringPool.SIZE));
+        } else {
+            stringPool = new ArrayList();
+        }
+        while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            switch (proto.getFieldNumber()) {
+                case (int) NotificationHistoryProto.StringPool.STRINGS:
+                    stringPool.add(proto.readString(NotificationHistoryProto.StringPool.STRINGS));
+                    break;
+            }
+        }
+        proto.end(token);
+        return stringPool;
+    }
+
+    private static void writeStringPool(ProtoOutputStream proto,
+            final NotificationHistory notifications) {
+        final long token = proto.start(NotificationHistoryProto.STRING_POOL);
+        final String[] pooledStrings = notifications.getPooledStringsToWrite();
+        proto.write(NotificationHistoryProto.StringPool.SIZE, pooledStrings.length);
+        for (int i = 0; i < pooledStrings.length; i++) {
+            proto.write(NotificationHistoryProto.StringPool.STRINGS, pooledStrings[i]);
+        }
+        proto.end(token);
+    }
+
+    private static void readNotification(ProtoInputStream proto, List<String> stringPool,
+            NotificationHistory notifications, NotificationHistoryFilter filter)
+            throws IOException {
+        final long token = proto.start(NotificationHistoryProto.NOTIFICATION);
+        try {
+            HistoricalNotification notification = readNotification(proto, stringPool);
+            if (filter.matchesPackageAndChannelFilter(notification)
+                    && filter.matchesCountFilter(notifications)) {
+                notifications.addNotificationToWrite(notification);
+            }
+        } catch (Exception e) {
+            Slog.e(TAG, "Error reading notification", e);
+        } finally {
+            proto.end(token);
+        }
+    }
+
+    private static HistoricalNotification readNotification(ProtoInputStream parser,
+            List<String> stringPool) throws IOException {
+        final HistoricalNotification.Builder notification = new HistoricalNotification.Builder();
+        String pkg = null;
+        while (true) {
+            switch (parser.nextField()) {
+                case (int) NotificationHistoryProto.Notification.PACKAGE:
+                    pkg = parser.readString(Notification.PACKAGE);
+                    notification.setPackage(pkg);
+                    stringPool.add(pkg);
+                    break;
+                case (int) Notification.PACKAGE_INDEX:
+                    pkg = stringPool.get(parser.readInt(Notification.PACKAGE_INDEX) - 1);
+                    notification.setPackage(pkg);
+                    break;
+                case (int) Notification.CHANNEL_NAME:
+                    String channelName = parser.readString(Notification.CHANNEL_NAME);
+                    notification.setChannelName(channelName);
+                    stringPool.add(channelName);
+                    break;
+                case (int) Notification.CHANNEL_NAME_INDEX:
+                    notification.setChannelName(stringPool.get(parser.readInt(
+                            Notification.CHANNEL_NAME_INDEX) - 1));
+                    break;
+                case (int) Notification.CHANNEL_ID:
+                    String channelId = parser.readString(Notification.CHANNEL_ID);
+                    notification.setChannelId(channelId);
+                    stringPool.add(channelId);
+                    break;
+                case (int) Notification.CHANNEL_ID_INDEX:
+                    notification.setChannelId(stringPool.get(parser.readInt(
+                            Notification.CHANNEL_ID_INDEX) - 1));
+                    break;
+                case (int) Notification.UID:
+                    notification.setUid(parser.readInt(Notification.UID));
+                    break;
+                case (int) Notification.USER_ID:
+                    notification.setUserId(parser.readInt(Notification.USER_ID));
+                    break;
+                case (int) Notification.POSTED_TIME_MS:
+                    notification.setPostedTimeMs(parser.readLong(Notification.POSTED_TIME_MS));
+                    break;
+                case (int) Notification.TITLE:
+                    notification.setTitle(parser.readString(Notification.TITLE));
+                    break;
+                case (int) Notification.TEXT:
+                    notification.setText(parser.readString(Notification.TEXT));
+                    break;
+                case (int) Notification.ICON:
+                    final long iconToken = parser.start(Notification.ICON);
+                    loadIcon(parser, notification, pkg);
+                    parser.end(iconToken);
+                    break;
+                case ProtoInputStream.NO_MORE_FIELDS:
+                    return notification.build();
+            }
+        }
+    }
+
+    private static void loadIcon(ProtoInputStream parser,
+            HistoricalNotification.Builder notification, String pkg) throws IOException {
+        int iconType = Notification.TYPE_UNKNOWN;
+        String imageBitmapFileName = null;
+        int imageResourceId = Resources.ID_NULL;
+        String imageResourceIdPackage = null;
+        byte[] imageByteData = null;
+        int imageByteDataLength = 0;
+        int imageByteDataOffset = 0;
+        String imageUri = null;
+
+        while (true) {
+            switch (parser.nextField()) {
+                case (int) Notification.Icon.IMAGE_TYPE:
+                    iconType = parser.readInt(Notification.Icon.IMAGE_TYPE);
+                    break;
+                case (int) Notification.Icon.IMAGE_DATA:
+                    imageByteData = parser.readBytes(Notification.Icon.IMAGE_DATA);
+                    break;
+                case (int) Notification.Icon.IMAGE_DATA_LENGTH:
+                    imageByteDataLength = parser.readInt(Notification.Icon.IMAGE_DATA_LENGTH);
+                    break;
+                case (int) Notification.Icon.IMAGE_DATA_OFFSET:
+                    imageByteDataOffset = parser.readInt(Notification.Icon.IMAGE_DATA_OFFSET);
+                    break;
+                case (int) Notification.Icon.IMAGE_BITMAP_FILENAME:
+                    imageBitmapFileName = parser.readString(
+                            Notification.Icon.IMAGE_BITMAP_FILENAME);
+                    break;
+                case (int) Notification.Icon.IMAGE_RESOURCE_ID:
+                    imageResourceId = parser.readInt(Notification.Icon.IMAGE_RESOURCE_ID);
+                    break;
+                case (int) Notification.Icon.IMAGE_RESOURCE_ID_PACKAGE:
+                    imageResourceIdPackage = parser.readString(
+                            Notification.Icon.IMAGE_RESOURCE_ID_PACKAGE);
+                    break;
+                case (int) Notification.Icon.IMAGE_URI:
+                    imageUri = parser.readString(Notification.Icon.IMAGE_URI);
+                    break;
+                case ProtoInputStream.NO_MORE_FIELDS:
+                    if (iconType == Icon.TYPE_DATA) {
+
+                        if (imageByteData != null) {
+                            notification.setIcon(Icon.createWithData(
+                                    imageByteData, imageByteDataOffset, imageByteDataLength));
+                        }
+                    } else if (iconType == Icon.TYPE_RESOURCE) {
+                        if (imageResourceId != Resources.ID_NULL) {
+                            notification.setIcon(Icon.createWithResource(
+                                    imageResourceIdPackage != null
+                                            ? imageResourceIdPackage
+                                            : pkg,
+                                    imageResourceId));
+                        }
+                    } else if (iconType == Icon.TYPE_URI) {
+                        if (imageUri != null) {
+                            notification.setIcon(Icon.createWithContentUri(imageUri));
+                        }
+                    } else if (iconType == Icon.TYPE_BITMAP) {
+                        // TODO: read file from disk
+                    }
+                    return;
+            }
+        }
+    }
+
+    private static void writeIcon(ProtoOutputStream proto, HistoricalNotification notification) {
+        final long token = proto.start(Notification.ICON);
+
+        proto.write(Notification.Icon.IMAGE_TYPE, notification.getIcon().getType());
+        switch (notification.getIcon().getType()) {
+            case Icon.TYPE_DATA:
+                proto.write(Notification.Icon.IMAGE_DATA, notification.getIcon().getDataBytes());
+                proto.write(Notification.Icon.IMAGE_DATA_LENGTH,
+                        notification.getIcon().getDataLength());
+                proto.write(Notification.Icon.IMAGE_DATA_OFFSET,
+                        notification.getIcon().getDataOffset());
+                break;
+            case Icon.TYPE_RESOURCE:
+                proto.write(Notification.Icon.IMAGE_RESOURCE_ID, notification.getIcon().getResId());
+                if (!notification.getPackage().equals(notification.getIcon().getResPackage())) {
+                    proto.write(Notification.Icon.IMAGE_RESOURCE_ID_PACKAGE,
+                            notification.getIcon().getResPackage());
+                }
+                break;
+            case Icon.TYPE_URI:
+                proto.write(Notification.Icon.IMAGE_URI, notification.getIcon().getUriString());
+                break;
+            case Icon.TYPE_BITMAP:
+                // TODO: write file to disk
+                break;
+        }
+
+        proto.end(token);
+    }
+
+    private static void writeNotification(ProtoOutputStream proto,
+            final String[] stringPool, final HistoricalNotification notification) {
+        final long token = proto.start(NotificationHistoryProto.NOTIFICATION);
+        final int packageIndex = Arrays.binarySearch(stringPool, notification.getPackage());
+        if (packageIndex >= 0) {
+            proto.write(Notification.PACKAGE_INDEX, packageIndex + 1);
+        } else {
+            // Package not in Stringpool for some reason, write full string instead
+            Slog.w(TAG, "notification package name (" + notification.getPackage()
+                    + ") not found in string cache");
+            proto.write(Notification.PACKAGE, notification.getPackage());
+        }
+        final int channelNameIndex = Arrays.binarySearch(stringPool, notification.getChannelName());
+        if (channelNameIndex >= 0) {
+            proto.write(Notification.CHANNEL_NAME_INDEX, channelNameIndex + 1);
+        } else {
+            Slog.w(TAG, "notification channel name (" + notification.getChannelName()
+                    + ") not found in string cache");
+            proto.write(Notification.CHANNEL_NAME, notification.getChannelName());
+        }
+        final int channelIdIndex = Arrays.binarySearch(stringPool, notification.getChannelId());
+        if (channelIdIndex >= 0) {
+            proto.write(Notification.CHANNEL_ID_INDEX, channelIdIndex + 1);
+        } else {
+            Slog.w(TAG, "notification channel id (" + notification.getChannelId()
+                    + ") not found in string cache");
+            proto.write(Notification.CHANNEL_ID, notification.getChannelId());
+        }
+        proto.write(Notification.UID, notification.getUid());
+        proto.write(Notification.USER_ID, notification.getUserId());
+        proto.write(Notification.POSTED_TIME_MS, notification.getPostedTimeMs());
+        proto.write(Notification.TITLE, notification.getTitle());
+        proto.write(Notification.TEXT, notification.getText());
+        writeIcon(proto, notification);
+        proto.end(token);
+    }
+
+    public static void read(InputStream in, NotificationHistory notifications,
+            NotificationHistoryFilter filter) throws IOException {
+        final ProtoInputStream proto = new ProtoInputStream(in);
+        List<String> stringPool = new ArrayList<>();
+        while (true) {
+            switch (proto.nextField()) {
+                case (int) NotificationHistoryProto.STRING_POOL:
+                    stringPool = readStringPool(proto);
+                    break;
+                case (int) NotificationHistoryProto.NOTIFICATION:
+                    readNotification(proto, stringPool, notifications, filter);
+                    break;
+                case ProtoInputStream.NO_MORE_FIELDS:
+                    if (filter.isFiltering()) {
+                        notifications.poolStringsFromNotifications();
+                    } else {
+                        notifications.addPooledStrings(stringPool);
+                    }
+                    return;
+            }
+        }
+    }
+
+    public static void write(OutputStream out, NotificationHistory notifications, int version) {
+        final ProtoOutputStream proto = new ProtoOutputStream(out);
+        proto.write(NotificationHistoryProto.MAJOR_VERSION, version);
+        // String pool should be written before the history itself
+        writeStringPool(proto, notifications);
+
+        List<HistoricalNotification> notificationsToWrite = notifications.getNotificationsToWrite();
+        final int count = notificationsToWrite.size();
+        for (int i = 0; i < count; i++) {
+            writeNotification(proto, notifications.getPooledStringsToWrite(),
+                    notificationsToWrite.get(i));
+        }
+
+        proto.flush();
+    }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index cd3343b..5e76401 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -415,6 +415,8 @@
     @GuardedBy("mNotificationLock")
     final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
     @GuardedBy("mNotificationLock")
+    final ArrayMap<String, InlineReplyUriRecord> mInlineReplyRecordsByKey = new ArrayMap<>();
+    @GuardedBy("mNotificationLock")
     final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
     @GuardedBy("mNotificationLock")
     final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
@@ -1167,42 +1169,53 @@
          * user associated with the NotificationRecord, and this grant will fail when trying
          * to grant URI permissions across users.
          */
-        public void grantInlineReplyUriPermission(String key, Uri uri, int callingUid) {
+        public void grantInlineReplyUriPermission(String key, Uri uri, UserHandle user,
+                String packageName, int callingUid) {
             synchronized (mNotificationLock) {
-                NotificationRecord r = mNotificationsByKey.get(key);
-                if (r != null) {
-                    IBinder owner = r.permissionOwner;
-                    if (owner == null) {
-                        r.permissionOwner = mUgmInternal.newUriPermissionOwner("NOTIF:" + key);
-                        owner = r.permissionOwner;
-                    }
-                    int uid = callingUid;
-                    int userId = r.sbn.getUserId();
-                    if (userId == UserHandle.USER_ALL) {
-                        userId = USER_SYSTEM;
-                    }
-                    if (UserHandle.getUserId(uid) != userId) {
-                        try {
-                            final String[] pkgs = mPackageManager.getPackagesForUid(callingUid);
-                            if (pkgs == null) {
-                                Log.e(TAG, "Cannot grant uri permission to unknown UID: "
-                                        + callingUid);
-                            }
-                            final String pkg = pkgs[0]; // Get the SystemUI package
-                            // Find the UID for SystemUI for the correct user
-                            uid =  mPackageManager.getPackageUid(pkg, 0, userId);
-                        } catch (RemoteException re) {
-                            Log.e(TAG, "Cannot talk to package manager", re);
+                InlineReplyUriRecord r = mInlineReplyRecordsByKey.get(key);
+                if (r == null) {
+                    InlineReplyUriRecord newRecord = new InlineReplyUriRecord(
+                            mUgmInternal.newUriPermissionOwner("INLINE_REPLY:" + key),
+                            user,
+                            packageName,
+                            key);
+                    r = newRecord;
+                    mInlineReplyRecordsByKey.put(key, r);
+                }
+                IBinder owner = r.getPermissionOwner();
+                int uid = callingUid;
+                int userId = r.getUserId();
+                if (UserHandle.getUserId(uid) != userId) {
+                    try {
+                        final String[] pkgs = mPackageManager.getPackagesForUid(callingUid);
+                        if (pkgs == null) {
+                            Log.e(TAG, "Cannot grant uri permission to unknown UID: "
+                                    + callingUid);
                         }
+                        final String pkg = pkgs[0]; // Get the SystemUI package
+                        // Find the UID for SystemUI for the correct user
+                        uid =  mPackageManager.getPackageUid(pkg, 0, userId);
+                    } catch (RemoteException re) {
+                        Log.e(TAG, "Cannot talk to package manager", re);
                     }
-                    grantUriPermission(owner, uri, uid, r.sbn.getPackageName(), userId);
-                } else {
-                    Log.w(TAG, "No record found for notification key:" + key);
+                }
+                r.addUri(uri);
+                grantUriPermission(owner, uri, uid, r.getPackageName(), userId);
+            }
+        }
 
-                    // TODO: figure out cancel story. I think it's: sysui needs to tell us
-                    // whenever noitifications held by a lifetimextender go away
-                    // IBinder owner = mUgmInternal.newUriPermissionOwner("InlineReply:" + key);
-                    // pass in userId and package as well as key (key for logging purposes)
+        @Override
+        /**
+         * Clears inline URI permission grants by destroying the permission owner for the specified
+         * notification.
+         */
+        public void clearInlineReplyUriPermissions(String key, int callingUid) {
+            synchronized (mNotificationLock) {
+                InlineReplyUriRecord uriRecord = mInlineReplyRecordsByKey.get(key);
+                if (uriRecord != null) {
+                    destroyPermissionOwner(uriRecord.getPermissionOwner(), uriRecord.getUserId(),
+                            "INLINE_REPLY: " + uriRecord.getKey());
+                    mInlineReplyRecordsByKey.remove(key);
                 }
             }
         }
@@ -7036,15 +7049,8 @@
 
         // If we have no Uris to grant, but an existing owner, go destroy it
         if (newUris == null && permissionOwner != null) {
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                if (DBG) Slog.d(TAG, key + ": destroying owner");
-                mUgmInternal.revokeUriPermissionFromOwner(permissionOwner, null, ~0,
-                        UserHandle.getUserId(oldRecord.getUid()));
-                permissionOwner = null;
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
+            destroyPermissionOwner(permissionOwner, UserHandle.getUserId(oldRecord.getUid()), key);
+            permissionOwner = null;
         }
 
         // Grant access to new Uris
@@ -7065,7 +7071,9 @@
                 final Uri uri = oldUris.valueAt(i);
                 if (newUris == null || !newUris.contains(uri)) {
                     if (DBG) Slog.d(TAG, key + ": revoking " + uri);
-                    revokeUriPermission(permissionOwner, uri, oldRecord.getUid());
+                    int userId = ContentProvider.getUserIdFromUri(
+                            uri, UserHandle.getUserId(oldRecord.getUid()));
+                    revokeUriPermission(permissionOwner, uri, userId);
                 }
             }
         }
@@ -7092,7 +7100,7 @@
         }
     }
 
-    private void revokeUriPermission(IBinder owner, Uri uri, int sourceUid) {
+    private void revokeUriPermission(IBinder owner, Uri uri, int userId) {
         if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
 
         final long ident = Binder.clearCallingIdentity();
@@ -7101,7 +7109,17 @@
                     owner,
                     ContentProvider.getUriWithoutUserId(uri),
                     Intent.FLAG_GRANT_READ_URI_PERMISSION,
-                    ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
+                    userId);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private void destroyPermissionOwner(IBinder owner, int userId, String logKey) {
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            if (DBG) Slog.d(TAG, logKey + ": destroying owner");
+            mUgmInternal.revokeUriPermissionFromOwner(owner, null, ~0, userId);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -7826,6 +7844,7 @@
                 R.array.config_allowedManagedServicesOnLowRamDevices)) {
             if (whitelisted.equals(pkg)) {
                 canUseManagedServices = true;
+                break;
             }
         }
 
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index 714bbb9..9a1b30d 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -25,7 +25,6 @@
 import android.os.BugreportParams;
 import android.os.IDumpstate;
 import android.os.IDumpstateListener;
-import android.os.IDumpstateToken;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -64,13 +63,6 @@
 
     @Override
     @RequiresPermission(android.Manifest.permission.DUMP)
-    public IDumpstateToken setListener(String name, IDumpstateListener listener,
-            boolean getSectionDetails) {
-        throw new UnsupportedOperationException("setListener is not allowed on this service");
-    }
-
-    @Override
-    @RequiresPermission(android.Manifest.permission.DUMP)
     public void startBugreport(int callingUidUnused, String callingPackage,
             FileDescriptor bugreportFd, FileDescriptor screenshotFd,
             int bugreportMode, IDumpstateListener listener) {
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index dc00cb4..12e8069 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -32,12 +32,14 @@
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
+import android.os.Environment;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.sysprop.ApexProperties;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.IndentingPrintWriter;
 
@@ -46,6 +48,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -63,9 +66,9 @@
     static final int MATCH_FACTORY_PACKAGE = 1 << 1;
 
     /**
-     * Returns an instance of either {@link ApexManagerImpl} or {@link ApexManagerNoOp} depending
-     * on whenever this device supports APEX, i.e. {@link ApexProperties#updatable()} evaluates to
-     * {@code true}.
+     * Returns an instance of either {@link ApexManagerImpl} or {@link ApexManagerFlattenedApex}
+     * depending on whether this device supports APEX, i.e. {@link ApexProperties#updatable()}
+     * evaluates to {@code true}.
      */
     static ApexManager create(Context systemContext) {
         if (ApexProperties.updatable().orElse(false)) {
@@ -76,10 +79,28 @@
                 throw new IllegalStateException("Required service apexservice not available");
             }
         } else {
-            return new ApexManagerNoOp();
+            return new ApexManagerFlattenedApex();
         }
     }
 
+    /**
+     * Minimal information about APEX mount points and the original APEX package they refer to.
+     */
+    static class ActiveApexInfo {
+        public final File apexDirectory;
+        public final File preinstalledApexPath;
+
+        private ActiveApexInfo(File apexDirectory, File preinstalledApexPath) {
+            this.apexDirectory = apexDirectory;
+            this.preinstalledApexPath = preinstalledApexPath;
+        }
+    }
+
+    /**
+     * Returns {@link ActiveApexInfo} records relative to all active APEX packages.
+     */
+    abstract List<ActiveApexInfo> getActiveApexInfos();
+
     abstract void systemReady();
 
     /**
@@ -217,7 +238,8 @@
      * An implementation of {@link ApexManager} that should be used in case device supports updating
      * APEX packages.
      */
-    private static class ApexManagerImpl extends ApexManager {
+    @VisibleForTesting
+    static class ApexManagerImpl extends ApexManager {
         private final IApexService mApexService;
         private final Context mContext;
         private final Object mLock = new Object();
@@ -257,6 +279,22 @@
         }
 
         @Override
+        List<ActiveApexInfo> getActiveApexInfos() {
+            try {
+                return Arrays.stream(mApexService.getActivePackages())
+                        .map(apexInfo -> new ActiveApexInfo(
+                                new File(
+                                Environment.getApexDirectory() + File.separator
+                                        + apexInfo.moduleName),
+                                new File(apexInfo.modulePath))).collect(
+                                Collectors.toList());
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Unable to retrieve packages from apexservice", e);
+            }
+            return Collections.emptyList();
+        }
+
+        @Override
         void systemReady() {
             mContext.registerReceiver(new BroadcastReceiver() {
                 @Override
@@ -335,8 +373,8 @@
                 if (!packageInfo.packageName.equals(packageName)) {
                     continue;
                 }
-                if ((!matchActive || isActive(packageInfo))
-                        && (!matchFactory || isFactory(packageInfo))) {
+                if ((matchActive && isActive(packageInfo))
+                        || (matchFactory && isFactory(packageInfo))) {
                     return packageInfo;
                 }
             }
@@ -547,7 +585,40 @@
      * An implementation of {@link ApexManager} that should be used in case device does not support
      * updating APEX packages.
      */
-    private static final class ApexManagerNoOp extends ApexManager {
+    private static final class ApexManagerFlattenedApex extends ApexManager {
+
+        @Override
+        List<ActiveApexInfo> getActiveApexInfos() {
+            // There is no apexd running in case of flattened apex
+            // We look up the /apex directory and identify the active APEX modules from there.
+            // As "preinstalled" path, we just report /system since in the case of flattened APEX
+            // the /apex directory is just a symlink to /system/apex.
+            List<ActiveApexInfo> result = new ArrayList<>();
+            File apexDir = Environment.getApexDirectory();
+            // In flattened configuration, init special-case the art directory and bind-mounts
+            // com.android.art.{release|debug} to com.android.art. At the time of writing, these
+            // directories are copied from the kArtApexDirNames variable in
+            // system/core/init/mount_namespace.cpp.
+            String[] skipDirs = {"com.android.art.release", "com.android.art.debug"};
+            if (apexDir.isDirectory()) {
+                File[] files = apexDir.listFiles();
+                // listFiles might be null if system server doesn't have permission to read
+                // a directory.
+                if (files != null) {
+                    for (File file : files) {
+                        if (file.isDirectory() && !file.getName().contains("@")) {
+                            for (String skipDir : skipDirs) {
+                                if (file.getName().equals(skipDir)) {
+                                    continue;
+                                }
+                            }
+                            result.add(new ActiveApexInfo(file, Environment.getRootDirectory()));
+                        }
+                    }
+                }
+            }
+            return result;
+        }
 
         @Override
         void systemReady() {
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index c8179a7..dc0cd18 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -41,7 +41,6 @@
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.FgThread;
-import com.android.server.compat.CompatConfig;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -131,11 +130,11 @@
 
     private static class FeatureConfigImpl implements FeatureConfig {
         private static final String FILTERING_ENABLED_NAME = "package_query_filtering_enabled";
+        private final PackageManagerService.Injector mInjector;
         private volatile boolean mFeatureEnabled = false;
-        private CompatConfig mCompatibility;
 
         private FeatureConfigImpl(PackageManagerService.Injector injector) {
-            mCompatibility = injector.getCompatibility();
+            mInjector = injector;
         }
 
         @Override
@@ -158,7 +157,7 @@
 
         @Override
         public boolean packageIsEnabled(PackageParser.Package pkg) {
-            return mCompatibility.isChangeEnabled(
+            return mInjector.getCompatibility().isChangeEnabled(
                     PackageManager.FILTER_APPLICATION_QUERY, pkg.applicationInfo);
         }
     }
@@ -263,10 +262,10 @@
      * Grants access based on an interaction between a calling and target package, granting
      * visibility of the caller from the target.
      *
-     * @param callingPackage    the package initiating the interaction
-     * @param targetPackage     the package being interacted with and thus gaining visibility of the
-     *                          initiating package.
-     * @param userId            the user in which this interaction was taking place
+     * @param callingPackage the package initiating the interaction
+     * @param targetPackage  the package being interacted with and thus gaining visibility of the
+     *                       initiating package.
+     * @param userId         the user in which this interaction was taking place
      */
     public void grantImplicitAccess(
             String callingPackage, String targetPackage, int userId) {
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index 1d3d24c..259200b 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -67,6 +67,15 @@
             codeRoot = Environment.getSystemExtDirectory();
         } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
             codeRoot = Environment.getOdmDirectory();
+        } else if (FileUtils.contains(Environment.getApexDirectory(), codePath)) {
+            String fullPath = codePath.getAbsolutePath();
+            String[] parts = fullPath.split(File.separator);
+            if (parts.length > 2) {
+                codeRoot = new File(parts[1] + File.separator + parts[2]);
+            } else {
+                Slog.w(PackageManagerService.TAG, "Can't canonicalize code path " + codePath);
+                codeRoot = Environment.getApexDirectory();
+            }
         } else {
             // Unrecognized code path; take its top real segment as the apk root:
             // e.g. /something/app/blah.apk => /something
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 00c0566..ed2bb3d5 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -259,7 +259,7 @@
         // Don't hold mSessions lock when calling restoreSession, since it might trigger an APK
         // atomic install which needs to query sessions, which requires lock on mSessions.
         for (PackageInstallerSession session : stagedSessionsToRestore) {
-            if (mPm.isDeviceUpgrading()) {
+            if (mPm.isDeviceUpgrading() && !session.isStagedAndInTerminalState()) {
                 session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
                         "Build fingerprint has changed");
             }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 104ce1c..340720e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -299,7 +299,7 @@
 import com.android.server.SystemConfig;
 import com.android.server.SystemServerInitThreadPool;
 import com.android.server.Watchdog;
-import com.android.server.compat.CompatConfig;
+import com.android.server.compat.PlatformCompat;
 import com.android.server.net.NetworkPolicyManagerInternal;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.Settings.DatabaseVersion;
@@ -370,6 +370,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
+import java.util.stream.Collectors;
 
 /**
  * Keep track of all those APKs everywhere.
@@ -750,17 +751,19 @@
     static final List<SystemPartition> SYSTEM_PARTITIONS = Collections.unmodifiableList(
             Arrays.asList(
                     new SystemPartition(Environment.getRootDirectory(), 0 /* scanFlag */,
-                            true /* hasPriv */, false /* hasOverlays */),
+                            false /* hasOverlays */),
                     new SystemPartition(Environment.getVendorDirectory(), SCAN_AS_VENDOR,
-                            true /* hasPriv */, true /* hasOverlays */),
+                            true /* hasOverlays */),
                     new SystemPartition(Environment.getOdmDirectory(), SCAN_AS_ODM,
-                            true /* hasPriv */, true /* hasOverlays */),
+                            true /* hasOverlays */),
                     new SystemPartition(Environment.getOemDirectory(), SCAN_AS_OEM,
-                            false /* hasPriv */, true /* hasOverlays */),
+                            true /* hasOverlays */),
                     new SystemPartition(Environment.getProductDirectory(), SCAN_AS_PRODUCT,
-                            true /* hasPriv */, true /* hasOverlays */),
+                            true /* hasOverlays */),
                     new SystemPartition(Environment.getSystemExtDirectory(), SCAN_AS_SYSTEM_EXT,
-                            true /* hasPriv */, true /* hasOverlays */)));
+                            true /* hasOverlays */)));
+
+    private final List<SystemPartition> mDirsToScanAsSystem;
 
     /**
      * Unit tests will instantiate, extend and/or mock to mock dependencies / behaviors.
@@ -834,7 +837,7 @@
         private final Singleton<StorageManager> mStorageManagerProducer;
         private final Singleton<AppOpsManager> mAppOpsManagerProducer;
         private final Singleton<AppsFilter> mAppsFilterProducer;
-        private final Singleton<CompatConfig> mPlatformCompatProducer;
+        private final Singleton<PlatformCompat> mPlatformCompatProducer;
 
         Injector(Context context, Object lock, Installer installer,
                 Object installLock, PackageAbiHelper abiHelper,
@@ -852,7 +855,7 @@
                 Producer<StorageManager> storageManagerProducer,
                 Producer<AppOpsManager> appOpsManagerProducer,
                 Producer<AppsFilter> appsFilterProducer,
-                Producer<CompatConfig> platformCompatProducer) {
+                Producer<PlatformCompat> platformCompatProducer) {
             mContext = context;
             mLock = lock;
             mInstaller = installer;
@@ -963,7 +966,7 @@
             return mAppsFilterProducer.get(this, mPackageManager);
         }
 
-        public CompatConfig getCompatibility() {
+        public PlatformCompat getCompatibility() {
             return mPlatformCompatProducer.get(this, mPackageManager);
         }
     }
@@ -2353,7 +2356,7 @@
                 new Injector.SystemServiceProducer<>(StorageManager.class),
                 new Injector.SystemServiceProducer<>(AppOpsManager.class),
                 (i, pm) -> AppsFilter.create(i),
-                (i, pm) -> CompatConfig.get());
+                (i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat"));
 
         PackageManagerService m = new PackageManagerService(injector, factoryTest, onlyCore);
         t.traceEnd(); // "create package manager"
@@ -2424,12 +2427,28 @@
         @Nullable
         public final File overlayFolder;
 
-        private SystemPartition(File folder, int scanFlag, boolean hasPrivApps,
-                boolean hasOverlays) {
+
+        private static boolean shouldScanPrivApps(@ScanFlags int scanFlags) {
+            if ((scanFlags & SCAN_AS_OEM) != 0) {
+                return false;
+            }
+            if (scanFlags == 0) {  // /system partition
+                return true;
+            }
+            if ((scanFlags
+                    & (SCAN_AS_VENDOR | SCAN_AS_ODM | SCAN_AS_PRODUCT | SCAN_AS_SYSTEM_EXT)) != 0) {
+                return true;
+            }
+            return false;
+        }
+
+        private SystemPartition(File folder, int scanFlag, boolean hasOverlays) {
             this.folder = folder;
             this.scanFlag = scanFlag;
             this.appFolder = toCanonical(new File(folder, "app"));
-            this.privAppFolder = hasPrivApps ? toCanonical(new File(folder, "priv-app")) : null;
+            this.privAppFolder = shouldScanPrivApps(scanFlag)
+                    ? toCanonical(new File(folder, "priv-app"))
+                    : null;
             this.overlayFolder = hasOverlays ? toCanonical(new File(folder, "overlay")) : null;
         }
 
@@ -2552,6 +2571,16 @@
         mApexManager = ApexManager.create(mContext);
         mAppsFilter = mInjector.getAppsFilter();
 
+        mDirsToScanAsSystem = new ArrayList<>();
+        mDirsToScanAsSystem.addAll(SYSTEM_PARTITIONS);
+        mDirsToScanAsSystem.addAll(mApexManager.getActiveApexInfos().stream()
+                .map(ai -> resolveApexToSystemPartition(ai))
+                .filter(Objects::nonNull).collect(Collectors.toList()));
+        Slog.d(TAG,
+                "Directories scanned as system partitions: [" + mDirsToScanAsSystem.stream().map(
+                        d -> (d.folder.getAbsolutePath() + ":" + d.scanFlag))
+                        .collect(Collectors.joining(",")) + "]");
+
         // CHECKSTYLE:OFF IndentationCheck
         synchronized (mInstallLock) {
         // writer
@@ -2684,8 +2713,8 @@
             // reside in the right directory.
             final int systemParseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR;
             final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM;
-            for (int i = SYSTEM_PARTITIONS.size() - 1; i >= 0; i--) {
-                final SystemPartition partition = SYSTEM_PARTITIONS.get(i);
+            for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
+                final SystemPartition partition = mDirsToScanAsSystem.get(i);
                 if (partition.overlayFolder == null) {
                     continue;
                 }
@@ -2699,8 +2728,8 @@
                 throw new IllegalStateException(
                         "Failed to load frameworks package; check log for warnings");
             }
-            for (int i = 0, size = SYSTEM_PARTITIONS.size(); i < size; i++) {
-                final SystemPartition partition = SYSTEM_PARTITIONS.get(i);
+            for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
+                final SystemPartition partition = mDirsToScanAsSystem.get(i);
                 if (partition.privAppFolder != null) {
                     scanDirTracedLI(partition.privAppFolder, systemParseFlags,
                             systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0);
@@ -2878,8 +2907,8 @@
 
                         @ParseFlags int reparseFlags = 0;
                         @ScanFlags int rescanFlags = 0;
-                        for (int i1 = 0, size = SYSTEM_PARTITIONS.size(); i1 < size; i1++) {
-                            SystemPartition partition = SYSTEM_PARTITIONS.get(i1);
+                        for (int i1 = 0, size = mDirsToScanAsSystem.size(); i1 < size; i1++) {
+                            SystemPartition partition = mDirsToScanAsSystem.get(i1);
                             if (partition.containsPrivApp(scanFile)) {
                                 reparseFlags = systemParseFlags;
                                 rescanFlags = systemScanFlags | SCAN_AS_PRIVILEGED
@@ -4092,7 +4121,7 @@
                 }
                 return generatePackageInfo(ps, flags, userId);
             }
-            if (!matchFactoryOnly && (flags & MATCH_APEX) != 0) {
+            if ((flags & MATCH_APEX) != 0) {
                 return mApexManager.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE);
             }
         }
@@ -8650,6 +8679,16 @@
             pkgSetting = originalPkgSetting == null ? installedPkgSetting : originalPkgSetting;
             pkgAlreadyExists = pkgSetting != null;
             final String disabledPkgName = pkgAlreadyExists ? pkgSetting.name : pkg.packageName;
+            if (scanSystemPartition && !pkgAlreadyExists
+                    && mSettings.getDisabledSystemPkgLPr(disabledPkgName) != null) {
+                // The updated-package data for /system apk remains inconsistently
+                // after the package data for /data apk is lost accidentally.
+                // To recover it, enable /system apk and install it as non-updated system app.
+                Slog.w(TAG, "Inconsistent package setting of updated system app for "
+                        + disabledPkgName + ". To recover it, enable the system app"
+                        + "and install it as non-updated system app.");
+                mSettings.removeDisabledSystemPackageLPw(disabledPkgName);
+            }
             disabledPkgSetting = mSettings.getDisabledSystemPkgLPr(disabledPkgName);
             isSystemPkgUpdated = disabledPkgSetting != null;
 
@@ -17777,17 +17816,19 @@
         }
     }
 
-    static boolean locationIsPrivileged(String path) {
+    private static @Nullable SystemPartition resolveApexToSystemPartition(
+            ApexManager.ActiveApexInfo apexInfo) {
         for (int i = 0, size = SYSTEM_PARTITIONS.size(); i < size; i++) {
-            SystemPartition partition = SYSTEM_PARTITIONS.get(i);
-            if (partition.containsPrivPath(path)) {
-                return true;
+            SystemPartition sp = SYSTEM_PARTITIONS.get(i);
+            if (apexInfo.preinstalledApexPath.getAbsolutePath().startsWith(
+                    sp.folder.getAbsolutePath())) {
+                return new SystemPartition(apexInfo.apexDirectory, sp.scanFlag,
+                        false /* hasOverlays */);
             }
         }
-        return false;
+        return null;
     }
 
-
     /*
      * Tries to delete system package.
      */
@@ -17897,8 +17938,8 @@
                 | PackageParser.PARSE_MUST_BE_APK
                 | PackageParser.PARSE_IS_SYSTEM_DIR;
         @ScanFlags int scanFlags = SCAN_AS_SYSTEM;
-        for (int i = 0, size = SYSTEM_PARTITIONS.size(); i < size; i++) {
-            SystemPartition partition = SYSTEM_PARTITIONS.get(i);
+        for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
+            SystemPartition partition = mDirsToScanAsSystem.get(i);
             if (partition.containsPath(codePathString)) {
                 scanFlags |= partition.scanFlag;
                 if (partition.containsPrivPath(codePathString)) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index a11ae8c..66c77f5 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3513,7 +3513,7 @@
         int pkgFlags = 0;
         int pkgPrivateFlags = 0;
         pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
-        if (PackageManagerService.locationIsPrivileged(codePathStr)) {
+        if (codePathStr.contains("/priv-app/")) {
             pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
         }
         PackageSetting ps = new PackageSetting(name, realName, new File(codePathStr),
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 8253b392..f0a1c70 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -495,7 +495,7 @@
 
     final private IUidObserver mUidObserver = new IUidObserver.Stub() {
         @Override
-        public void onUidStateChanged(int uid, int procState, long procStateSeq) {
+        public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) {
             injectPostToHandler(() -> handleOnUidStateChanged(uid, procState));
         }
 
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index cfc5ca0..5c9b9c9 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -871,7 +871,7 @@
                     "target should only be specified when we are disabling quiet mode.");
         }
 
-        ensureCanModifyQuietMode(callingPackage, Binder.getCallingUid(), target != null);
+        ensureCanModifyQuietMode(callingPackage, Binder.getCallingUid(), userId, target != null);
         final long identity = Binder.clearCallingIdentity();
         try {
             boolean result = false;
@@ -903,13 +903,15 @@
      *     <li>Has system UID or root UID</li>
      *     <li>Has {@link Manifest.permission#MODIFY_QUIET_MODE}</li>
      *     <li>Has {@link Manifest.permission#MANAGE_USERS}</li>
+     *     <li>Is the foreground default launcher app</li>
      * </ul>
      * <p>
-     * If caller wants to start an intent after disabling the quiet mode, it must has
+     * If caller wants to start an intent after disabling the quiet mode, or if it is targeting a
+     * user in a different profile group from the caller, it must have
      * {@link Manifest.permission#MANAGE_USERS}.
      */
     private void ensureCanModifyQuietMode(String callingPackage, int callingUid,
-            boolean startIntent) {
+            @UserIdInt int targetUserId, boolean startIntent) {
         if (hasManageUsersPermission()) {
             return;
         }
@@ -917,6 +919,10 @@
             throw new SecurityException("MANAGE_USERS permission is required to start intent "
                     + "after disabling quiet mode.");
         }
+        if (!isSameProfileGroupNoChecks(UserHandle.getUserId(callingUid), targetUserId)) {
+            throw new SecurityException("MANAGE_USERS permission is required to modify quiet mode "
+                    + "for a different profile group.");
+        }
         final boolean hasModifyQuietModePermission = hasPermissionGranted(
                 Manifest.permission.MODIFY_QUIET_MODE, callingUid);
         if (hasModifyQuietModePermission) {
@@ -1587,6 +1593,7 @@
     /** @return a specific user restriction that's in effect currently. */
     @Override
     public boolean hasUserRestriction(String restrictionKey, @UserIdInt int userId) {
+        checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "hasUserRestriction");
         return mLocalService.hasUserRestriction(restrictionKey, userId);
     }
 
@@ -1711,6 +1718,7 @@
      */
     @Override
     public Bundle getUserRestrictions(@UserIdInt int userId) {
+        checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "getUserRestrictions");
         return UserRestrictionsUtils.clone(getEffectiveUserRestrictions(userId));
     }
 
@@ -2986,8 +2994,8 @@
                 // Must start user (which will be stopped right away, through
                 // UserController.finishUserUnlockedCompleted) so services can properly
                 // intialize it.
-                // TODO(b/140750212): in the long-term, we should add a onCreateUser() callback
-                // on SystemService instead.
+                // TODO(b/143092698): in the long-term, it might be better to add a onCreateUser()
+                // callback on SystemService instead.
                 Slog.i(LOG_TAG, "starting pre-created user " + userInfo.toFullString());
                 final IActivityManager am = ActivityManager.getService();
                 try {
@@ -3003,7 +3011,7 @@
             Binder.restoreCallingIdentity(ident);
         }
 
-        // TODO(b/140750212): it's possible to reach "max users overflow" when the user is created
+        // TODO(b/143092698): it's possible to reach "max users overflow" when the user is created
         // "from scratch" (i.e., not from a pre-created user) and reaches the maximum number of
         // users without counting the pre-created one. Then when the pre-created is converted, the
         // "effective" number of max users is exceeds. Example:
@@ -3048,7 +3056,7 @@
      * <p>Should be used only during user creation, so the pre-created user can be used (instead of
      * creating and initializing a new user from scratch).
      */
-    // TODO(b/140750212): add unit test
+    // TODO(b/143092698): add unit test
     @GuardedBy("mUsersLock")
     private @Nullable UserData getPreCreatedUserLU(@UserInfoFlag int flags) {
         if (DBG) {
@@ -3994,9 +4002,14 @@
         long now = System.currentTimeMillis();
         final long nowRealtime = SystemClock.elapsedRealtime();
 
-        final int currentUser = LocalServices.getService(ActivityManagerInternal.class)
-                .getCurrentUserId();
-        pw.print("Current user: "); pw.println(currentUser);
+        final ActivityManagerInternal amInternal = LocalServices
+                .getService(ActivityManagerInternal.class);
+        pw.print("Current user: ");
+        if (amInternal != null) {
+            pw.println(amInternal.getCurrentUserId());
+        } else {
+            pw.println("N/A");
+        }
 
         StringBuilder sb = new StringBuilder();
         synchronized (mPackagesLock) {
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index 323c957..ef6b24c 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -49,13 +49,14 @@
  * <p>If {@link #isEnforceMode()} is false, then all system packages are always installed for all
  * users. The following applies when it is true.
  *
- * Any package can be in one of three states in the SystemConfig whitelist
+ * <p>Any package can be in one of three states in the {@code SystemConfig} whitelist
  * <ol>
  *     <li>Explicitly blacklisted for a particular user type</li>
  *     <li>Explicitly whitelisted for a particular user type</li>
  *     <li>Not mentioned at all, for any user type (neither whitelisted nor blacklisted)</li>
  * </ol>
- * Blacklisting always takes precedence - if a package is blacklisted for a particular user,
+ *
+ * <p>Blacklisting always takes precedence - if a package is blacklisted for a particular user,
  * it won't be installed on that type of user (even if it is also whitelisted for that user).
  * Next comes whitelisting - if it is whitelisted for a particular user, it will be installed on
  * that type of user (as long as it isn't blacklisted).
@@ -69,6 +70,12 @@
  *     <li>Either way, for {@link UserHandle#USER_SYSTEM}, the package will be implicitly
  *          whitelisted so that it can be used for local development purposes.</li>
  * </ul>
+ *
+ * <p><b>NOTE:</b> the {@code SystemConfig} state is only updated on first boot or after a system
+ * update. So, to verify changes during development, you can emulate the latter by calling:
+ * <pre><code>
+ * adb shell setprop persist.pm.mock-upgrade true
+ * </code></pre>
  */
 class UserSystemPackageInstaller {
     private static final String TAG = "UserManagerService";
@@ -109,13 +116,13 @@
      * <p>Packages that are whitelisted, but then blacklisted so that they aren't to be installed on
      * any user, are purposefully still present in this list.
      */
-    private final ArrayMap<String, Integer> mWhitelitsedPackagesForUserTypes;
+    private final ArrayMap<String, Integer> mWhitelistedPackagesForUserTypes;
 
     private final UserManagerService mUm;
 
     UserSystemPackageInstaller(UserManagerService ums) {
         mUm = ums;
-        mWhitelitsedPackagesForUserTypes =
+        mWhitelistedPackagesForUserTypes =
                 determineWhitelistedPackagesForUserTypes(SystemConfig.getInstance());
     }
 
@@ -123,7 +130,7 @@
     @VisibleForTesting
     UserSystemPackageInstaller(UserManagerService ums, ArrayMap<String, Integer> whitelist) {
         mUm = ums;
-        mWhitelitsedPackagesForUserTypes = whitelist;
+        mWhitelistedPackagesForUserTypes = whitelist;
     }
 
     /**
@@ -242,7 +249,7 @@
         return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST) != 0;
     }
 
-    /** Gets the PackageWhitelistMode for use of {@link #mWhitelitsedPackagesForUserTypes}. */
+    /** Gets the PackageWhitelistMode for use of {@link #mWhitelistedPackagesForUserTypes}. */
     private @PackageWhitelistMode int getWhitelistMode() {
         final int runtimeMode = SystemProperties.getInt(
                 PACKAGE_WHITELIST_MODE_PROP, USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT);
@@ -283,7 +290,7 @@
             if (!pkg.isSystem()) {
                 return;
             }
-            if (shouldInstallPackage(pkg, mWhitelitsedPackagesForUserTypes,
+            if (shouldInstallPackage(pkg, mWhitelistedPackagesForUserTypes,
                     whitelistedPackages, isImplicitWhitelistMode, isSystemUser)) {
                 // Although the whitelist uses manifest names, this function returns packageNames.
                 installPackages.add(pkg.packageName);
@@ -333,10 +340,10 @@
      */
     @VisibleForTesting
     @NonNull Set<String> getWhitelistedPackagesForUserType(int flags) {
-        Set<String> installablePkgs = new ArraySet<>(mWhitelitsedPackagesForUserTypes.size());
-        for (int i = 0; i < mWhitelitsedPackagesForUserTypes.size(); i++) {
-            String pkgName = mWhitelitsedPackagesForUserTypes.keyAt(i);
-            int whitelistedUserTypes = mWhitelitsedPackagesForUserTypes.valueAt(i);
+        Set<String> installablePkgs = new ArraySet<>(mWhitelistedPackagesForUserTypes.size());
+        for (int i = 0; i < mWhitelistedPackagesForUserTypes.size(); i++) {
+            String pkgName = mWhitelistedPackagesForUserTypes.keyAt(i);
+            int whitelistedUserTypes = mWhitelistedPackagesForUserTypes.valueAt(i);
             if ((flags & whitelistedUserTypes) != 0) {
                 installablePkgs.add(pkgName);
             }
@@ -353,7 +360,7 @@
      * completely blacklists an AOSP app).
      */
     private Set<String> getWhitelistedSystemPackages() {
-        return mWhitelitsedPackagesForUserTypes.keySet();
+        return mWhitelistedPackagesForUserTypes.keySet();
     }
 
     /**
@@ -449,18 +456,28 @@
     }
 
     void dump(PrintWriter pw) {
-        pw.print("Whitelisted packages per user type");
-        final int size = mWhitelitsedPackagesForUserTypes.size();
+        final String prefix = "    ";
+        final int mode = getWhitelistMode();
+        pw.println("Whitelisted packages per user type");
+        pw.print(prefix); pw.print("Mode: ");
+        pw.print(mode);
+        pw.print(isEnforceMode(mode) ? " (enforced)" : "");
+        pw.print(isLogMode(mode) ? " (logged)" : "");
+        pw.print(isImplicitWhitelistMode(mode) ? " (implicit)" : "");
+        pw.println();
+
+        final int size = mWhitelistedPackagesForUserTypes.size();
         if (size == 0) {
-            pw.println(": N/A");
+            pw.print(prefix); pw.println("No packages");
             return;
         }
-        pw.println(" (" + size + " packages)");
+        final String prefix2 = prefix + prefix;
+        pw.print(prefix); pw.print(size); pw.println(" packages:");
         for (int i = 0; i < size; i++) {
-            final String pkgName = mWhitelitsedPackagesForUserTypes.keyAt(i);
+            final String pkgName = mWhitelistedPackagesForUserTypes.keyAt(i);
             final String whitelistedUserTypes =
-                    UserInfo.flagsToString(mWhitelitsedPackagesForUserTypes.valueAt(i));
-            pw.println("    " + pkgName + ": " + whitelistedUserTypes);
+                    UserInfo.flagsToString(mWhitelistedPackagesForUserTypes.valueAt(i));
+            pw.print(prefix2); pw.print(pkgName); pw.print(": "); pw.println(whitelistedUserTypes);
         }
     }
 }
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index f56231f..41dcaa5 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -16,8 +16,6 @@
 
 package com.android.server.pm.dex;
 
-import static android.provider.DeviceConfig.NAMESPACE_DEX_BOOT;
-
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;
 import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo;
@@ -31,7 +29,6 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
-import android.provider.DeviceConfig;
 import android.util.Log;
 import android.util.Slog;
 import android.util.jar.StrictJarFile;
@@ -72,10 +69,6 @@
     private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST =
             "pm.dexopt.priv-apps-oob-list";
 
-    // flags for Device Config API
-    private static final String PRIV_APPS_OOB_ENABLED = "priv_apps_oob_enabled";
-    private static final String PRIV_APPS_OOB_WHITELIST = "priv_apps_oob_whitelist";
-
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private final Context mContext;
@@ -717,24 +710,16 @@
         return isPackageSelectedToRunOobInternal(
                 SystemProperties.getBoolean(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB, false),
                 SystemProperties.get(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST, "ALL"),
-                DeviceConfig.getProperty(NAMESPACE_DEX_BOOT, PRIV_APPS_OOB_ENABLED),
-                DeviceConfig.getProperty(NAMESPACE_DEX_BOOT, PRIV_APPS_OOB_WHITELIST),
                 packageNamesInSameProcess);
     }
 
     @VisibleForTesting
-    /* package */ static boolean isPackageSelectedToRunOobInternal(
-            boolean isDefaultEnabled, String defaultWhitelist, String overrideEnabled,
-            String overrideWhitelist, Collection<String> packageNamesInSameProcess) {
-        // Allow experiment (if exists) to override device configuration.
-        boolean enabled = overrideEnabled != null ? overrideEnabled.equals("true")
-                : isDefaultEnabled;
-        if (!enabled) {
+    /* package */ static boolean isPackageSelectedToRunOobInternal(boolean isEnabled,
+            String whitelist, Collection<String> packageNamesInSameProcess) {
+        if (!isEnabled) {
             return false;
         }
 
-        // Similarly, experiment flag can override the whitelist.
-        String whitelist = overrideWhitelist != null ? overrideWhitelist : defaultWhitelist;
         if ("ALL".equals(whitelist)) {
             return true;
         }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 2593c38..5e1d93f 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -386,6 +386,7 @@
     BurnInProtectionHelper mBurnInProtectionHelper;
     private DisplayFoldController mDisplayFoldController;
     AppOpsManager mAppOpsManager;
+    PackageManager mPackageManager;
     private boolean mHasFeatureAuto;
     private boolean mHasFeatureWatch;
     private boolean mHasFeatureLeanback;
@@ -1555,10 +1556,9 @@
     private void launchAllAppsAction() {
         Intent intent = new Intent(Intent.ACTION_ALL_APPS);
         if (mHasFeatureLeanback) {
-            final PackageManager pm = mContext.getPackageManager();
             Intent intentLauncher = new Intent(Intent.ACTION_MAIN);
             intentLauncher.addCategory(Intent.CATEGORY_HOME);
-            ResolveInfo resolveInfo = pm.resolveActivityAsUser(intentLauncher,
+            ResolveInfo resolveInfo = mPackageManager.resolveActivityAsUser(intentLauncher,
                     PackageManager.MATCH_SYSTEM_ONLY,
                     mCurrentUserId);
             if (resolveInfo != null) {
@@ -1753,10 +1753,11 @@
         mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
         mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
         mDisplayManager = mContext.getSystemService(DisplayManager.class);
-        mHasFeatureWatch = mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH);
-        mHasFeatureLeanback = mContext.getPackageManager().hasSystemFeature(FEATURE_LEANBACK);
-        mHasFeatureAuto = mContext.getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE);
-        mHasFeatureHdmiCec = mContext.getPackageManager().hasSystemFeature(FEATURE_HDMI_CEC);
+        mPackageManager = mContext.getPackageManager();
+        mHasFeatureWatch = mPackageManager.hasSystemFeature(FEATURE_WATCH);
+        mHasFeatureLeanback = mPackageManager.hasSystemFeature(FEATURE_LEANBACK);
+        mHasFeatureAuto = mPackageManager.hasSystemFeature(FEATURE_AUTOMOTIVE);
+        mHasFeatureHdmiCec = mPackageManager.hasSystemFeature(FEATURE_HDMI_CEC);
         mAccessibilityShortcutController =
                 new AccessibilityShortcutController(mContext, new Handler(), mCurrentUserId);
         mLogger = new MetricsLogger();
@@ -1994,7 +1995,7 @@
         }
 
         mShortPressOnWindowBehavior = SHORT_PRESS_WINDOW_NOTHING;
-        if (mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
+        if (mPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
             mShortPressOnWindowBehavior = SHORT_PRESS_WINDOW_PICTURE_IN_PICTURE;
         }
     }
@@ -2138,7 +2139,7 @@
 
         ApplicationInfo appInfo;
         try {
-            appInfo = mContext.getPackageManager().getApplicationInfoAsUser(
+            appInfo = mPackageManager.getApplicationInfoAsUser(
                             attrs.packageName,
                             0 /* flags */,
                             UserHandle.getUserId(callingUid));
@@ -4914,7 +4915,7 @@
             @Override public void run() {
                 if (mBootMsgDialog == null) {
                     int theme;
-                    if (mContext.getPackageManager().hasSystemFeature(FEATURE_LEANBACK)) {
+                    if (mPackageManager.hasSystemFeature(FEATURE_LEANBACK)) {
                         theme = com.android.internal.R.style.Theme_Leanback_Dialog_Alert;
                     } else {
                         theme = 0;
@@ -4943,7 +4944,7 @@
                             return true;
                         }
                     };
-                    if (mContext.getPackageManager().isDeviceUpgrading()) {
+                    if (mPackageManager.isDeviceUpgrading()) {
                         mBootMsgDialog.setTitle(R.string.android_upgrading_title);
                     } else {
                         mBootMsgDialog.setTitle(R.string.android_start_title);
@@ -5203,7 +5204,7 @@
         }
 
         ActivityInfo ai = null;
-        ResolveInfo info = mContext.getPackageManager().resolveActivityAsUser(
+        ResolveInfo info = mPackageManager.resolveActivityAsUser(
                 intent,
                 PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA,
                 mCurrentUserId);
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index ef4c12e..198bb14 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -53,6 +53,7 @@
 import android.util.SparseBooleanArray;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.LocalServices;
 import com.android.server.Watchdog;
@@ -469,44 +470,39 @@
             List<Rollback> restoreInProgress = new ArrayList<>();
             Set<String> apexPackageNames = new HashSet<>();
             synchronized (mLock) {
-                for (Rollback rollback : mRollbacks) {
-                    if (rollback.isStaged()) {
+                Iterator<Rollback> iter = mRollbacks.iterator();
+                while (iter.hasNext()) {
+                    Rollback rollback = iter.next();
+                    if (!rollback.isStaged()) {
+                        // We only care about staged rollbacks here
+                        continue;
+                    }
+
+                    PackageInstaller.SessionInfo session = mContext.getPackageManager()
+                            .getPackageInstaller().getSessionInfo(rollback.getStagedSessionId());
+                    if (session == null || session.isStagedSessionFailed()) {
+                        iter.remove();
+                        rollback.delete(mAppDataRollbackHelper);
+                        continue;
+                    }
+
+                    if (session.isStagedSessionApplied()) {
                         if (rollback.isEnabling()) {
                             enabling.add(rollback);
                         } else if (rollback.isRestoreUserDataInProgress()) {
                             restoreInProgress.add(rollback);
                         }
-
-                        apexPackageNames.addAll(rollback.getApexPackageNames());
                     }
+                    apexPackageNames.addAll(rollback.getApexPackageNames());
                 }
             }
 
             for (Rollback rollback : enabling) {
-                PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
-                PackageInstaller.SessionInfo session =
-                        installer.getSessionInfo(rollback.getStagedSessionId());
-                if (session == null || session.isStagedSessionFailed()) {
-                    // TODO: Do we need to remove this from
-                    // mRollbacks, or is it okay to leave as
-                    // unavailable until the next reboot when it will go
-                    // away on its own?
-                    rollback.delete(mAppDataRollbackHelper);
-                } else if (session.isStagedSessionApplied()) {
-                    makeRollbackAvailable(rollback);
-                }
+                makeRollbackAvailable(rollback);
             }
 
             for (Rollback rollback : restoreInProgress) {
-                PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
-                PackageInstaller.SessionInfo session =
-                        installer.getSessionInfo(rollback.getStagedSessionId());
-                // TODO: What if session is null?
-                if (session != null) {
-                    if (session.isStagedSessionApplied() || session.isStagedSessionFailed()) {
-                        rollback.setRestoreUserDataInProgress(false);
-                    }
-                }
+                rollback.setRestoreUserDataInProgress(false);
             }
 
             for (String apexPackageName : apexPackageNames) {
@@ -1133,6 +1129,8 @@
 
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+
         IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
         synchronized (mLock) {
             for (Rollback rollback : mRollbacks) {
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 489c343..effeb80 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -1364,12 +1364,26 @@
     }
 
     @Override
-    public void grantInlineReplyUriPermission(String key, Uri uri) {
+    public void grantInlineReplyUriPermission(String key, Uri uri, UserHandle user,
+            String packageName) {
         enforceStatusBarService();
         int callingUid = Binder.getCallingUid();
         long identity = Binder.clearCallingIdentity();
         try {
-            mNotificationDelegate.grantInlineReplyUriPermission(key, uri, callingUid);
+            mNotificationDelegate.grantInlineReplyUriPermission(key, uri, user, packageName,
+                    callingUid);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void clearInlineReplyUriPermissions(String key) {
+        enforceStatusBarService();
+        int callingUid = Binder.getCallingUid();
+        long identity = Binder.clearCallingIdentity();
+        try {
+            mNotificationDelegate.clearInlineReplyUriPermissions(key, callingUid);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 5493afd..403d342 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -30,6 +30,7 @@
 import android.service.textclassifier.ITextClassifierCallback;
 import android.service.textclassifier.ITextClassifierService;
 import android.service.textclassifier.TextClassifierService;
+import android.service.textclassifier.TextClassifierService.ConnectionState;
 import android.util.ArrayMap;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -130,6 +131,10 @@
     }
 
     @Override
+    public void onConnectedStateChanged(@ConnectionState int connected) {
+    }
+
+    @Override
     public void onSuggestSelection(
             @Nullable TextClassificationSessionId sessionId,
             TextSelection.Request request, ITextClassifierCallback callback)
@@ -579,6 +584,11 @@
             @Override
             public void onServiceConnected(ComponentName name, IBinder service) {
                 init(ITextClassifierService.Stub.asInterface(service));
+                try {
+                    mService.onConnectedStateChanged(TextClassifierService.CONNECTED);
+                } catch (RemoteException e) {
+                    Slog.e(LOG_TAG, "error in onConnectedStateChanged");
+                }
             }
 
             @Override
diff --git a/services/core/java/com/android/server/twilight/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java
index e4cb19e..e72ba8d 100644
--- a/services/core/java/com/android/server/twilight/TwilightService.java
+++ b/services/core/java/com/android/server/twilight/TwilightService.java
@@ -17,6 +17,7 @@
 package com.android.server.twilight;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.AlarmManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -160,8 +161,13 @@
         // Request the device's location immediately if a previous location isn't available.
         if (mLocationManager.getLastLocation() == null) {
             if (mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
-                mLocationManager.requestSingleUpdate(
-                        LocationManager.NETWORK_PROVIDER, this, Looper.getMainLooper());
+                mLocationManager.getCurrentLocation(
+                        LocationManager.NETWORK_PROVIDER, null, getContext().getMainExecutor(),
+                        this::onLocationChanged);
+            } else if (mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
+                mLocationManager.getCurrentLocation(
+                        LocationManager.GPS_PROVIDER, null, getContext().getMainExecutor(),
+                        this::onLocationChanged);
             }
         }
 
@@ -218,12 +224,7 @@
                 for (int i = mListeners.size() - 1; i >= 0; --i) {
                     final TwilightListener listener = mListeners.keyAt(i);
                     final Handler handler = mListeners.valueAt(i);
-                    handler.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            listener.onTwilightStateChanged(state);
-                        }
-                    });
+                    handler.post(() -> listener.onTwilightStateChanged(state));
                 }
             }
         }
@@ -243,12 +244,8 @@
     }
 
     @Override
-    public void onLocationChanged(Location location) {
-        // Location providers may erroneously return (0.0, 0.0) when they fail to determine the
-        // device's location. These location updates can be safely ignored since the chance of a
-        // user actually being at these coordinates is quite low.
-        if (location != null
-                && !(location.getLongitude() == 0.0 && location.getLatitude() == 0.0)) {
+    public void onLocationChanged(@Nullable Location location) {
+        if (location != null) {
             Slog.d(TAG, "onLocationChanged:"
                     + " provider=" + location.getProvider()
                     + " accuracy=" + location.getAccuracy()
diff --git a/services/core/java/com/android/server/updates/EmergencyNumberDbInstallReceiver.java b/services/core/java/com/android/server/updates/EmergencyNumberDbInstallReceiver.java
index 852f707..cb0b45c 100644
--- a/services/core/java/com/android/server/updates/EmergencyNumberDbInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/EmergencyNumberDbInstallReceiver.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.telephony.TelephonyManager;
 import android.util.Slog;
 
 /**
@@ -34,6 +35,11 @@
     @Override
     protected void postInstall(Context context, Intent intent) {
         Slog.i(TAG, "Emergency number database is updated in file partition");
-        // TODO Send a notification to EmergencyNumberTracker for updating of emergency number db.
+
+        // Notify EmergencyNumberTracker for emergency number installation complete.
+        Intent notifyInstallComplete = new Intent(
+                TelephonyManager.ACTION_OTA_EMERGENCY_NUMBER_DB_INSTALLED);
+        context.sendBroadcast(
+                notifyInstallComplete, android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
     }
 }
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index b131ab6..c57ac11 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -116,6 +116,14 @@
         return result;
     }
 
+    /**
+     * Sets a callback for observing which windows are touchable for the purposes
+     * of accessibility on specified display.
+     *
+     * @param displayId The logical display id.
+     * @param callback The callback.
+     * @return {@code false} if display id is not valid or an embedded display.
+     */
     public boolean setWindowsForAccessibilityCallbackLocked(int displayId,
             WindowsForAccessibilityCallback callback) {
         if (callback != null) {
@@ -124,17 +132,20 @@
                 return false;
             }
 
-            if (mWindowsForAccessibilityObserver.get(displayId) != null) {
-                final Display display = dc.getDisplay();
-                if (display.getType() == Display.TYPE_VIRTUAL && dc.getParentWindow() != null) {
-                    // The window observer of this embedded display had been set from
-                    // window manager after setting its parent window.
-                    return true;
-                } else {
-                    throw new IllegalStateException(
-                            "Windows for accessibility callback of display "
-                                    + displayId + " already set!");
+            final Display display = dc.getDisplay();
+            if (display.getType() == Display.TYPE_VIRTUAL && dc.getParentWindow() != null) {
+                // If this display is an embedded one, its window observer should have been set from
+                // window manager after setting its parent window. But if its window observer is
+                // empty, that means this mapping didn't be set, and needs to do this again.
+                // This happened when accessibility window observer is disabled and enabled again.
+                if (mWindowsForAccessibilityObserver.get(displayId) == null) {
+                    handleWindowObserverOfEmbeddedDisplayLocked(displayId, dc.getParentWindow());
                 }
+                return false;
+            } else if (mWindowsForAccessibilityObserver.get(displayId) != null) {
+                throw new IllegalStateException(
+                        "Windows for accessibility callback of display "
+                                + displayId + " already set!");
             }
             mWindowsForAccessibilityObserver.put(displayId,
                     new WindowsForAccessibilityObserver(mService, displayId, callback));
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 9d41d97..ff2c671 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -403,8 +403,7 @@
 
         if (launchedActivity != null && launchedActivity.mDrawn) {
             // Launched activity is already visible. We cannot measure windows drawn delay.
-            reset(true /* abort */, info, "launched activity already visible",
-                0L /* timestampNs */);
+            abort(info, "launched activity already visible");
             return;
         }
 
@@ -422,8 +421,7 @@
         if ((!isLoggableResultCode(resultCode) || launchedActivity == null || !processSwitch
                 || windowingMode == WINDOWING_MODE_UNDEFINED) && !otherWindowModesLaunching) {
             // Failed to launch or it was not a process switch, so we don't care about the timing.
-            reset(true /* abort */, info, "failed to launch or not a process switch",
-                0L /* timestampNs */);
+            abort(info, "failed to launch or not a process switch");
             return;
         } else if (otherWindowModesLaunching) {
             // Don't log this windowing mode but continue with the other windowing modes.
@@ -469,8 +467,7 @@
         final WindowingModeTransitionInfoSnapshot infoSnapshot =
                 new WindowingModeTransitionInfoSnapshot(info);
         if (allWindowsDrawn() && mLoggedTransitionStarting) {
-            reset(false /* abort */, info, "notifyWindowsDrawn - all windows drawn",
-                timestampNs /* timestampNs */);
+            reset(false /* abort */, info, "notifyWindowsDrawn - all windows drawn", timestampNs);
         }
         return infoSnapshot;
     }
@@ -478,13 +475,13 @@
     /**
      * Notifies the tracker that the starting window was drawn.
      */
-    void notifyStartingWindowDrawn(@WindowingMode int windowingMode, long timestamp) {
+    void notifyStartingWindowDrawn(@WindowingMode int windowingMode, long timestampNs) {
         final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
         if (info == null || info.loggedStartingWindowDrawn) {
             return;
         }
         info.loggedStartingWindowDrawn = true;
-        info.startingWindowDelayMs = calculateDelay(timestamp);
+        info.startingWindowDelayMs = calculateDelay(timestampNs);
     }
 
     /**
@@ -544,10 +541,11 @@
         mHandler.obtainMessage(MSG_CHECK_VISIBILITY, args).sendToTarget();
     }
 
-    private boolean hasVisibleNonFinishingActivity(TaskRecord t) {
+    /** @return {@code true} if the given task has an activity will be drawn. */
+    private static boolean hasActivityToBeDrawn(TaskRecord t) {
         for (int i = t.getChildCount() - 1; i >= 0; --i) {
             final ActivityRecord r = t.getChildAt(i);
-            if (r.visible && !r.finishing) {
+            if (r.visible && !r.mDrawn && !r.finishing) {
                 return true;
             }
         }
@@ -574,19 +572,20 @@
                 return;
             }
 
-            // Check if there is any activity in the task that is visible and not finishing. If the
-            // launched activity finished before it is drawn and if there is another activity in
-            // the task then that activity will be draw on screen.
-            if (hasVisibleNonFinishingActivity(t)) {
+            // If the task of the launched activity contains any activity to be drawn, then the
+            // window drawn event should report later to complete the transition. Otherwise all
+            // activities in this task may be finished, invisible or drawn, so the transition event
+            // should be cancelled.
+            if (hasActivityToBeDrawn(t)) {
                 return;
             }
 
             if (DEBUG_METRICS) Slog.i(TAG, "notifyVisibilityChanged to invisible activity=" + r);
             logAppTransitionCancel(info);
-            mWindowingModeTransitionInfo.remove(r.getWindowingMode());
-            if (mWindowingModeTransitionInfo.size() == 0) {
-                reset(true /* abort */, info, "notifyVisibilityChanged to invisible",
-                    0L /* timestampNs */);
+            // Abort if this is the only one active transition.
+            if (mWindowingModeTransitionInfo.size() == 1
+                    && mWindowingModeTransitionInfo.get(r.getWindowingMode()) != null) {
+                abort(info, "notifyVisibilityChanged to invisible");
             }
         }
     }
@@ -622,19 +621,25 @@
                 && mWindowingModeTransitionInfo.size() > 0;
     }
 
+    /** Aborts tracking of current launch metrics. */
+    private void abort(WindowingModeTransitionInfo info, String cause) {
+        reset(true /* abort */, info, cause, 0L /* timestampNs */);
+    }
+
     private void reset(boolean abort, WindowingModeTransitionInfo info, String cause,
-        long timestampNs) {
+            long timestampNs) {
+        final boolean isAnyTransitionActive = isAnyTransitionActive();
         if (DEBUG_METRICS) {
-            Slog.i(TAG,
-                "reset abort=" + abort + ",cause=" + cause + ",timestamp=" + timestampNs);
+            Slog.i(TAG, "reset abort=" + abort + " cause=" + cause + " timestamp=" + timestampNs
+                    + " active=" + isAnyTransitionActive);
         }
-        if (!abort && isAnyTransitionActive()) {
+        if (!abort && isAnyTransitionActive) {
             logAppTransitionMultiEvents();
         }
         stopLaunchTrace(info);
 
         // Ignore reset-after reset.
-        if (isAnyTransitionActive()) {
+        if (isAnyTransitionActive) {
             // LaunchObserver callbacks.
             if (abort) {
                 launchObserverNotifyActivityLaunchCancelled(info);
@@ -818,7 +823,14 @@
             return StatsLog.APP_START_OCCURRED__TYPE__HOT;
         }
         return StatsLog.APP_START_OCCURRED__TYPE__UNKNOWN;
-     }
+    }
+
+    /** @return the last known window drawn delay of the given windowing mode. */
+    int getLastDrawnDelayMs(@WindowingMode int windowingMode) {
+        final WindowingModeTransitionInfo info = mLastWindowingModeTransitionInfo.get(
+                windowingMode);
+        return info != null ? info.windowsDrawnDelayMs : INVALID_DELAY;
+    }
 
     WindowingModeTransitionInfoSnapshot logAppTransitionReportedDrawn(ActivityRecord r,
             boolean restoredFromBundle) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 3853841..db219fd 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -137,10 +137,8 @@
 import static com.android.server.wm.ActivityStack.ActivityState.STARTED;
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
-import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_APP;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
@@ -181,7 +179,7 @@
 import static com.android.server.wm.AppWindowTokenProto.FROZEN_BOUNDS;
 import static com.android.server.wm.AppWindowTokenProto.HIDDEN_REQUESTED;
 import static com.android.server.wm.AppWindowTokenProto.HIDDEN_SET_FROM_TRANSFERRED_STARTING_WINDOW;
-import static com.android.server.wm.AppWindowTokenProto.IS_REALLY_ANIMATING;
+import static com.android.server.wm.AppWindowTokenProto.IS_ANIMATING;
 import static com.android.server.wm.AppWindowTokenProto.IS_WAITING_FOR_TRANSITION_START;
 import static com.android.server.wm.AppWindowTokenProto.LAST_ALL_DRAWN;
 import static com.android.server.wm.AppWindowTokenProto.LAST_SURFACE_SHOWING;
@@ -207,16 +205,17 @@
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
 import static com.android.server.wm.TaskPersister.DEBUG;
 import static com.android.server.wm.TaskPersister.IMAGE_EXTENSION;
+import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
+import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
-import static com.android.server.wm.WindowManagerService.logWithStack;
 import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY;
 import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
-import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
 
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -293,16 +292,17 @@
 import android.view.InputApplicationHandle;
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationDefinition;
+import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 import android.view.animation.Animation;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.ReferrerIntent;
-import com.android.internal.R;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.internal.util.XmlUtils;
 import com.android.server.AttributeCache;
@@ -317,6 +317,7 @@
 import com.android.server.wm.ActivityMetricsLogger.WindowingModeTransitionInfoSnapshot;
 import com.android.server.wm.ActivityStack.ActivityState;
 import com.android.server.wm.WindowManagerService.H;
+import com.android.server.wm.utils.InsetUtils;
 
 import com.google.android.collect.Sets;
 
@@ -334,7 +335,6 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
-import java.util.function.Consumer;
 
 /**
  * An entry in the history stack, representing an activity.
@@ -376,6 +376,7 @@
      * Value to increment the z-layer when boosting a layer during animations. BOOST in l33tsp34k.
      */
     @VisibleForTesting static final int Z_BOOST_BASE = 800570000;
+    static final int INVALID_PID = -1;
 
     final ActivityTaskManagerService mAtmService;
     final ActivityInfo info; // activity info provided by developer in AndroidManifest
@@ -426,8 +427,8 @@
     // Last configuration reported to the activity in the client process.
     private MergedConfiguration mLastReportedConfiguration;
     private int mLastReportedDisplayId;
-    private boolean mLastReportedMultiWindowMode;
-    private boolean mLastReportedPictureInPictureMode;
+    boolean mLastReportedMultiWindowMode;
+    boolean mLastReportedPictureInPictureMode;
     CompatibilityInfo compat;// last used compatibility mode
     ActivityRecord resultTo; // who started this entry, so will get our reply
     final String resultWho; // additional identifier for use by resultTo.
@@ -490,7 +491,7 @@
     long lastLaunchTime;    // time of last launch of this activity
     ComponentName requestedVrComponent; // the requested component for handling VR mode.
 
-    private boolean inHistory;  // are we in the history stack?
+    boolean inHistory;  // are we in the history stack?
     final ActivityStackSupervisor mStackSupervisor;
     final RootActivityContainer mRootActivityContainer;
 
@@ -530,10 +531,6 @@
     // True if we are current in the process of removing this app token from the display
     private boolean mRemovingFromDisplay = false;
 
-    // Flag set while reparenting to prevent actions normally triggered by an individual parent
-    // change.
-    private boolean mReparenting;
-
     private RemoteAnimationDefinition mRemoteAnimationDefinition;
 
     private AnimatingActivityRegistry mAnimatingActivityRegistry;
@@ -557,24 +554,6 @@
     private boolean mCurrentLaunchCanTurnScreenOn = true;
 
     /**
-     * This gets used during some open/close transitions as well as during a change transition
-     * where it represents the starting-state snapshot.
-     */
-    private AppWindowThumbnail mThumbnail;
-    private final Rect mTransitStartRect = new Rect();
-
-    /**
-     * If we are running an animation, this determines the transition type. Must be one of
-     * AppTransition.TRANSIT_* constants.
-     */
-    private int mTransit;
-
-    /**
-     * If we are running an animation, this determines the flags during this animation. Must be a
-     * bitwise combination of AppTransition.TRANSIT_FLAG_* constants.
-     */
-    private int mTransitFlags;
-    /**
      * This leash is used to "freeze" the app surface in place after the state change, but before
      * the animation is ready to start.
      */
@@ -608,7 +587,6 @@
     private long mLastTransactionSequence = Long.MIN_VALUE;
     private int mNumInterestingWindows;
     private int mNumDrawnWindows;
-    boolean inPendingTransaction;
     boolean allDrawn;
     private boolean mLastAllDrawn;
 
@@ -670,7 +648,6 @@
     // TODO: Have a WindowContainer state for tracking exiting/deferred removal.
     boolean mIsExiting;
 
-    boolean mLaunchTaskBehind;
     boolean mEnteringAnimation;
 
     boolean mAppStopped;
@@ -682,15 +659,6 @@
     ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
     ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
 
-    /** Whether this token should be boosted at the top of all app window tokens. */
-    @VisibleForTesting boolean mNeedsZBoost;
-
-    /** Layer used to constrain the animation to a token's stack bounds. */
-    SurfaceControl mAnimationBoundsLayer;
-
-    /** Whether this token needs to create mAnimationBoundsLayer for cropping animations. */
-    boolean mNeedsAnimationBoundsLayer;
-
     private AppSaturationInfo mLastAppSaturationInfo;
 
     private final ColorDisplayService.ColorTransformController mColorTransformController =
@@ -716,10 +684,6 @@
     private final Configuration mTmpConfig = new Configuration();
     private final Rect mTmpBounds = new Rect();
 
-    private final Point mTmpPoint = new Point();
-    private final Rect mTmpRect = new Rect();
-    private final Rect mTmpPrevBounds = new Rect();
-
     // Token for targeting this activity for assist purposes.
     final Binder assistToken = new Binder();
 
@@ -751,7 +715,7 @@
                 pw.print(" launchedFromPackage="); pw.print(launchedFromPackage);
                 pw.print(" userId="); pw.println(mUserId);
         pw.print(prefix); pw.print("app="); pw.println(app);
-        pw.print(prefix); pw.println(intent.toInsecureStringWithClip());
+        pw.print(prefix); pw.println(intent.toInsecureString());
         pw.print(prefix); pw.print("rootOfTask="); pw.print(isRootOfTask());
                 pw.print(" task="); pw.println(task);
         pw.print(prefix); pw.print("taskAffinity="); pw.println(taskAffinity);
@@ -846,7 +810,7 @@
                 if (intent == null) {
                     pw.println("null");
                 } else {
-                    pw.println(intent.toShortString(false, true, false, true));
+                    pw.println(intent.toShortString(false, true, false, false));
                 }
             }
         }
@@ -911,15 +875,10 @@
             pw.print(prefix); pw.print("mNumInterestingWindows=");
             pw.print(mNumInterestingWindows);
             pw.print(" mNumDrawnWindows="); pw.print(mNumDrawnWindows);
-            pw.print(" inPendingTransaction="); pw.print(inPendingTransaction);
             pw.print(" allDrawn="); pw.print(allDrawn);
             pw.print(" lastAllDrawn="); pw.print(mLastAllDrawn);
             pw.println(")");
         }
-        if (inPendingTransaction) {
-            pw.print(prefix); pw.print("inPendingTransaction=");
-            pw.println(inPendingTransaction);
-        }
         if (mStartingData != null || removed || firstWindowDrawn || mIsExiting) {
             pw.print(prefix); pw.print("startingData="); pw.print(mStartingData);
             pw.print(" removed="); pw.print(removed);
@@ -1189,7 +1148,7 @@
         }
     }
 
-    // TODO: Remove once TaskRecord and Task are unified.
+    // TODO(task-unify): Remove once TaskRecord and Task are unified.
     TaskRecord getTaskRecord() {
         return task;
     }
@@ -1201,16 +1160,8 @@
      * {@link ActivityStack}.
      * @param task The new parent {@link TaskRecord}.
      */
+    // TODO(task-unify): Can be remove after task level unification. Callers can just use addChild
     void setTask(TaskRecord task) {
-        setTask(task /* task */, false /* reparenting */);
-    }
-
-    /**
-     * This method should only be called by {@link TaskRecord#removeActivity(ActivityRecord)}.
-     * @param task          The new parent task.
-     * @param reparenting   Whether we're in the middle of reparenting.
-     */
-    void setTask(TaskRecord task, boolean reparenting) {
         // Do nothing if the {@link TaskRecord} is the same as the current {@link getTaskRecord}.
         if (task != null && task == getTaskRecord()) {
             return;
@@ -1222,7 +1173,7 @@
         // Inform old stack (if present) of activity removal and new stack (if set) of activity
         // addition.
         if (oldStack != newStack) {
-            if (!reparenting && oldStack != null) {
+            if (oldStack != null) {
                 oldStack.onActivityRemovedFromStack(this);
             }
 
@@ -1231,39 +1182,18 @@
             }
         }
 
+        final TaskRecord oldTask = this.task;
         this.task = task;
 
         // This is attaching the activity to the task which we only want to do once.
-        // TODO: Need to re-work after unifying the task level since it will already have a parent
-        // then. Just need to restructure the re-parent case not to do this. NOTE that the
-        // reparenting flag passed in can't be used directly for this as it isn't set in
+        // TODO(task-unify): Need to re-work after unifying the task level since it will already
+        // have a parent then. Just need to restructure the re-parent case not to do this. NOTE that
+        // the reparenting flag passed in can't be used directly for this as it isn't set in
         // ActivityRecord#reparent() case that ends up calling this method.
         if (task != null && getParent() == null) {
-            inHistory = true;
-            final Task container = task.getTask();
-            if (container != null) {
-                onAttachToTask(task.voiceSession != null, container.getDisplayContent(),
-                        getInputDispatchingTimeoutLocked(this) * 1000000L);
-                ProtoLog.v(WM_DEBUG_ADD_REMOVE, "setTask: %s at top.", this);
-                container.addChild(this, Integer.MAX_VALUE /* add on top */);
-            }
-
-            // TODO(b/36505427): Maybe this call should be moved inside
-            // updateOverrideConfiguration()
-            task.updateOverrideConfigurationFromLaunchBounds();
-            // Make sure override configuration is up-to-date before using to create window
-            // controller.
-            updateOverrideConfiguration();
-
-            task.addActivityToTop(this);
-
-            // When an activity is started directly into a split-screen fullscreen stack, we need to
-            // update the initial multi-window modes so that the callbacks are scheduled correctly
-            // when the user leaves that mode.
-            mLastReportedMultiWindowMode = inMultiWindowMode();
-            mLastReportedPictureInPictureMode = inPinnedWindowingMode();
-        } else if (!reparenting) {
-            onParentChanged();
+            task.addChild(this);
+        } else {
+            onParentChanged(task, oldTask);
         }
     }
 
@@ -1289,24 +1219,46 @@
     }
 
     @Override
-    void onParentChanged() {
-        super.onParentChanged();
+    void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
+        final TaskRecord oldTask = (oldParent != null) ? ((Task) oldParent).mTaskRecord : null;
+        final TaskRecord newTask = (newParent != null) ? ((Task) newParent).mTaskRecord : null;
+        this.task = newTask;
+
+        super.onParentChanged(newParent, oldParent);
 
         final Task task = getTask();
 
+        if (oldParent == null && newParent != null) {
+            // First time we are adding the activity to the system.
+            // TODO(task-unify): See if mVoiceInteraction variable is really needed after task level
+            // unification.
+            mVoiceInteraction = task.mTaskRecord != null && task.mTaskRecord.voiceSession != null;
+            mInputDispatchingTimeoutNanos = getInputDispatchingTimeoutLocked(this) * 1000000L;
+            onDisplayChanged(task.getDisplayContent());
+            if (task.mTaskRecord != null) {
+                task.mTaskRecord.updateOverrideConfigurationFromLaunchBounds();
+            }
+            // Make sure override configuration is up-to-date before using to create window
+            // controller.
+            updateSizeCompatMode();
+            // When an activity is started directly into a split-screen fullscreen stack, we need to
+            // update the initial multi-window modes so that the callbacks are scheduled correctly
+            // when the user leaves that mode.
+            mLastReportedMultiWindowMode = inMultiWindowMode();
+            mLastReportedPictureInPictureMode = inPinnedWindowingMode();
+        }
+
         // When the associated task is {@code null}, the {@link ActivityRecord} can no longer
         // access visual elements like the {@link DisplayContent}. We must remove any associations
         // such as animations.
-        if (!mReparenting) {
-            if (task == null) {
-                // It is possible we have been marked as a closing app earlier. We must remove ourselves
-                // from this list so we do not participate in any future animations.
-                if (getDisplayContent() != null) {
-                    getDisplayContent().mClosingApps.remove(this);
-                }
-            } else if (mLastParent != null && mLastParent.mStack != null) {
-                task.mStack.mExitingActivities.remove(this);
+        if (task == null) {
+            // It is possible we have been marked as a closing app earlier. We must remove ourselves
+            // from this list so we do not participate in any future animations.
+            if (getDisplayContent() != null) {
+                getDisplayContent().mClosingApps.remove(this);
             }
+        } else if (mLastParent != null && mLastParent.mStack != null) {
+            task.mStack.mExitingActivities.remove(this);
         }
         final TaskStack stack = getStack();
 
@@ -1321,6 +1273,21 @@
         mLastParent = task;
 
         updateColorTransform();
+
+        final ActivityStack oldStack = (oldTask != null) ? oldTask.getStack() : null;
+        final ActivityStack newStack = (newTask != null) ? newTask.getStack() : null;
+        // Inform old stack (if present) of activity removal and new stack (if set) of activity
+        // addition.
+        if (oldStack != newStack) {
+            // TODO(task-unify): Might be better to use onChildAdded and onChildRemoved signal for
+            // this once task level is unified.
+            if (oldStack !=  null) {
+                oldStack.onActivityRemovedFromStack(this);
+            }
+            if (newStack !=  null) {
+                newStack.onActivityAddedToStack(this);
+            }
+        }
     }
 
     private void updateColorTransform() {
@@ -1698,17 +1665,6 @@
         return hasProcess() && app.hasThread();
     }
 
-    void onAttachToTask(boolean voiceInteraction, DisplayContent dc,
-            long inputDispatchingTimeoutNanos) {
-        mInputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
-        mVoiceInteraction = voiceInteraction;
-        onDisplayChanged(dc);
-
-        // Application tokens start out hidden.
-        setHidden(true);
-        hiddenRequested = true;
-    }
-
     boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
             CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
             IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
@@ -1968,12 +1924,12 @@
         });
     }
 
-    void removeWindowContainer() {
+    private void removeAppTokenFromDisplay() {
         if (mWmService.mRoot == null) return;
 
         final DisplayContent dc = mWmService.mRoot.getDisplayContent(getDisplayId());
         if (dc == null) {
-            Slog.w(TAG, "removeWindowContainer: Attempted to remove token: "
+            Slog.w(TAG, "removeAppTokenFromDisplay: Attempted to remove token: "
                     + appToken + " from non-existing displayId=" + getDisplayId());
             return;
         }
@@ -2006,56 +1962,17 @@
                     + " r=" + this + " (" + prevTask.getStackId() + ")");
         }
 
-        final Task task = newTask.getTask();
-        ProtoLog.i(WM_DEBUG_ADD_REMOVE, "reparent: moving app token=%s"
+        ProtoLog.i(WM_DEBUG_ADD_REMOVE, "reparent: moving activity=%s"
                 + " to task=%d at %d", this, task.mTaskId, position);
 
-        if (task == null) {
-            throw new IllegalArgumentException("reparent: could not find task");
-        }
-        final Task currentTask = getTask();
-        if (task == currentTask) {
-            throw new IllegalArgumentException(
-                    "window token=" + this + " already child of task=" + currentTask);
-        }
+        reparent(newTask.getTask(), position);
+    }
 
-        if (currentTask.mStack != task.mStack) {
-            throw new IllegalArgumentException(
-                    "window token=" + this + " current task=" + currentTask
-                            + " belongs to a different stack than " + task);
-        }
-
-        ProtoLog.i(WM_DEBUG_ADD_REMOVE, "reParentWindowToken: removing window token=%s"
-                + " from task=%s"  , this, currentTask);
-        final DisplayContent prevDisplayContent = getDisplayContent();
-
-        mReparenting = true;
-
-        getParent().removeChild(this);
-        task.addChild(this, position);
-
-        mReparenting = false;
-
-        // Relayout display(s).
-        final DisplayContent displayContent = task.getDisplayContent();
-        displayContent.setLayoutNeeded();
-        if (prevDisplayContent != displayContent) {
-            onDisplayChanged(displayContent);
-            prevDisplayContent.setLayoutNeeded();
-        }
-        getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
-
-        // Reparenting prevents informing the parent stack of activity removal in the case that
-        // the new stack has the same parent. we must manually signal here if this is not the case.
-        final ActivityStack prevStack = prevTask.getStack();
-
-        if (prevStack != newTask.getStack()) {
-            prevStack.onActivityRemovedFromStack(this);
-        }
-        // Remove the activity from the old task and add it to the new task.
-        prevTask.removeActivity(this, true /* reparenting */);
-
-        newTask.addActivityAtIndex(position, this);
+    // TODO(task-unify): Remove once Task level is unified.
+    void onParentChanged(TaskRecord newParent, TaskRecord oldParent) {
+        onParentChanged(
+                newParent != null ? newParent.mTask : null,
+                oldParent != null ? oldParent.mTask : null);
     }
 
     private boolean isHomeIntent(Intent intent) {
@@ -2353,7 +2270,7 @@
      * 2. App is delayed closing since it might enter PIP.
      */
     boolean isClosingOrEnteringPip() {
-        return (isAnimating() && hiddenRequested) || mWillCloseOrEnterPip;
+        return (isAnimating(TRANSITION | PARENTS) && hiddenRequested) || mWillCloseOrEnterPip;
     }
     /**
      * @return Whether AppOps allows this package to enter picture-in-picture.
@@ -2520,7 +2437,9 @@
         }
 
         final ActivityStack stack = getActivityStack();
-        final boolean mayAdjustFocus = (isState(RESUMED) || stack.mResumedActivity == null)
+        final boolean mayAdjustTop = (isState(RESUMED) || stack.mResumedActivity == null)
+                && stack.isFocusedStackOnDisplay();
+        final boolean shouldAdjustGlobalFocus = mayAdjustTop
                 // It must be checked before {@link #makeFinishingLocked} is called, because a stack
                 // is not visible if it only contains finishing activities.
                 && mRootActivityContainer.isTopDisplayFocusedStack(stack);
@@ -2548,9 +2467,21 @@
 
             // We are finishing the top focused activity and its stack has nothing to be focused so
             // the next focusable stack should be focused.
-            if (mayAdjustFocus
+            if (mayAdjustTop
                     && (stack.topRunningActivityLocked() == null || !stack.isFocusable())) {
-                stack.adjustFocusToNextFocusableStack("finish-top");
+                if (shouldAdjustGlobalFocus) {
+                    // Move the entire hierarchy to top with updating global top resumed activity
+                    // and focused application if needed.
+                    stack.adjustFocusToNextFocusableStack("finish-top");
+                } else {
+                    // Only move the next stack to top in its display.
+                    final ActivityDisplay display = stack.getDisplay();
+                    final ActivityRecord next = display.topRunningActivity();
+                    if (next != null) {
+                        display.positionChildAtTop(next.getActivityStack(),
+                                false /* includingParents */, "finish-display-top");
+                    }
+                }
             }
 
             finishActivityResults(resultCode, resultData);
@@ -2680,20 +2611,12 @@
         // implied that the current finishing activity should be added into stopping list rather
         // than destroy immediately.
         final boolean isNextNotYetVisible = next != null && (!next.nowVisible || !next.visible);
-        final boolean notGlobalFocusedStack =
-                getActivityStack() != mRootActivityContainer.getTopDisplayFocusedStack();
         if (isVisible && isNextNotYetVisible) {
             // Add this activity to the list of stopping activities. It will be processed and
             // destroyed when the next activity reports idle.
             addToStopping(false /* scheduleIdle */, false /* idleDelayed */,
                     "completeFinishing");
             setState(STOPPING, "completeFinishing");
-            if (notGlobalFocusedStack) {
-                // Ensuring visibility and configuration only for non-focused stacks since this
-                // method call is relatively expensive and not necessary for focused stacks.
-                mRootActivityContainer.ensureVisibilityAndConfig(next, getDisplayId(),
-                        false /* markFrozenIfConfigChanged */, true /* deferResume */);
-            }
         } else if (addToFinishingAndWaitForIdle()) {
             // We added this activity to the finishing list and something else is becoming resumed.
             // The activity will complete finishing when the next activity reports idle. No need to
@@ -2896,6 +2819,8 @@
     }
 
     /** Note: call {@link #cleanUp(boolean, boolean)} before this method. */
+    // TODO(task-unify): Look into consolidating this with TaskRecord.removeChild once we unify
+    // task level.
     void removeFromHistory(String reason) {
         finishActivityResults(Activity.RESULT_CANCELED, null /* resultData */);
         makeFinishingLocked();
@@ -2913,41 +2838,7 @@
         setState(DESTROYED, "removeFromHistory");
         if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + this);
         app = null;
-        removeWindowContainer();
-        final TaskRecord task = getTaskRecord();
-        final boolean lastActivity = task.removeActivity(this);
-        // If we are removing the last activity in the task, not including task overlay activities,
-        // then fall through into the block below to remove the entire task itself
-        final boolean onlyHasTaskOverlays =
-                task.onlyHasTaskOverlayActivities(false /* excludingFinishing */);
-
-        if (lastActivity || onlyHasTaskOverlays) {
-            if (DEBUG_STATES) {
-                Slog.i(TAG, "removeFromHistory: last activity removed from " + this
-                        + " onlyHasTaskOverlays=" + onlyHasTaskOverlays);
-            }
-
-            // The following block can be executed multiple times if there is more than one overlay.
-            // {@link ActivityStackSupervisor#removeTaskByIdLocked} handles this by reverse lookup
-            // of the task by id and exiting early if not found.
-            if (onlyHasTaskOverlays) {
-                // When destroying a task, tell the supervisor to remove it so that any activity it
-                // has can be cleaned up correctly. This is currently the only place where we remove
-                // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays
-                // state into removeTask(), we just clear the task here before the other residual
-                // work.
-                // TODO: If the callers to removeTask() changes such that we have multiple places
-                //       where we are destroying the task, move this back into removeTask()
-                mStackSupervisor.removeTaskByIdLocked(task.mTaskId, false /* killProcess */,
-                        !REMOVE_FROM_RECENTS, reason);
-            }
-
-            // We must keep the task around until all activities are destroyed. The following
-            // statement will only execute once since overlays are also considered activities.
-            if (lastActivity) {
-                stack.removeTask(task, reason, REMOVE_TASK_MODE_DESTROYING);
-            }
-        }
+        removeAppTokenFromDisplay();
 
         cleanUpActivityServices();
         removeUriPermissionsLocked();
@@ -3188,7 +3079,7 @@
 
         ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
                 "Removing app %s delayed=%b animation=%s animating=%b", this, delayed,
-                getAnimation(), isSelfAnimating());
+                getAnimation(), isAnimating(TRANSITION));
 
         ProtoLog.v(WM_DEBUG_ADD_REMOVE, "removeAppToken: %s"
                 + " delayed=%b Callers=%s", this, delayed, Debug.getCallers(4));
@@ -3200,7 +3091,7 @@
         // If this window was animating, then we need to ensure that the app transition notifies
         // that animations have completed in DisplayContent.handleAnimatingStoppedAndTransition(),
         // so add to that list now
-        if (isSelfAnimating()) {
+        if (isAnimating(TRANSITION)) {
             getDisplayContent().mNoAnimationNotifyOnTransitionFinished.add(token);
         }
 
@@ -3548,7 +3439,7 @@
      *         color mode set to avoid jank in the middle of the transition.
      */
     boolean canShowWindows() {
-        return allDrawn && !(isReallyAnimating() && hasNonDefaultColorWindow());
+        return allDrawn && !(isAnimating() && hasNonDefaultColorWindow());
     }
 
     /**
@@ -3610,17 +3501,17 @@
         return forAllWindowsUnchecked(callback, traverseTopToBottom);
     }
 
-    @Override
-    void forAllActivities(Consumer<ActivityRecord> callback) {
-        callback.accept(this);
-    }
-
     boolean forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback,
             boolean traverseTopToBottom) {
         return super.forAllWindows(callback, traverseTopToBottom);
     }
 
     @Override
+    boolean forAllActivities(ToBooleanFunction<ActivityRecord> callback) {
+        return callback.apply(this);
+    }
+
+    @Override
     protected void setLayer(Transaction t, int layer) {
         if (!mSurfaceAnimator.hasLeash()) {
             t.setLayer(mSurfaceControl, layer);
@@ -4139,7 +4030,6 @@
         // If we are preparing an app transition, then delay changing
         // the visibility of this token until we execute that transition.
         if (okToAnimate() && appTransition.isTransitionSet()) {
-            inPendingTransaction = true;
             if (visible) {
                 displayContent.mOpeningApps.add(this);
                 mEnteringAnimation = true;
@@ -4173,7 +4063,6 @@
             boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) {
 
         boolean delayed = false;
-        inPendingTransaction = false;
         // Reset the state of mHiddenSetFromTransferredStartingWindow since visibility is actually
         // been set by the app now.
         mHiddenSetFromTransferredStartingWindow = false;
@@ -4201,8 +4090,8 @@
 
             if (transit != WindowManager.TRANSIT_UNSET) {
                 if (mUseTransferredAnimation) {
-                    runningAppAnimation = isReallyAnimating();
-                } else if (applyAnimationLocked(lp, transit, visible, isVoiceInteraction)) {
+                    runningAppAnimation = isAnimating();
+                } else if (applyAnimation(lp, transit, visible, isVoiceInteraction)) {
                     runningAppAnimation = true;
                 }
                 delayed = runningAppAnimation;
@@ -4253,21 +4142,14 @@
         }
         mUseTransferredAnimation = false;
 
-        if (isReallyAnimating()) {
-            delayed = true;
-        } else {
+        delayed = isAnimating(CHILDREN);
+        if (!delayed) {
             // We aren't animating anything, but exiting windows rely on the animation finished
             // callback being called in case the ActivityRecord was pretending to be animating,
             // which we might have done because we were in closing/opening apps list.
             onAnimationFinished();
         }
 
-        for (int i = mChildren.size() - 1; i >= 0 && !delayed; i--) {
-            if ((mChildren.get(i)).isSelfOrChildAnimating()) {
-                delayed = true;
-            }
-        }
-
         if (visibilityChanged) {
             if (visible && !delayed) {
                 // The token was made immediately visible, there will be no entrance animation.
@@ -4282,7 +4164,7 @@
             // updated.
             // If we're becoming invisible, update the client visibility if we are not running an
             // animation. Otherwise, we'll update client visibility in onAnimationFinished.
-            if (visible || !isReallyAnimating()) {
+            if (visible || !isAnimating()) {
                 setClientHidden(!visible);
             }
 
@@ -4519,34 +4401,30 @@
         removeStartingWindow();
     }
 
-    void notifyUnknownVisibilityLaunched() {
-
+    /**
+     * Suppress transition until the new activity becomes ready, otherwise the keyguard can appear
+     * for a short amount of time before the new process with the new activity had the ability to
+     * set its showWhenLocked flags.
+     */
+    void notifyUnknownVisibilityLaunchedForKeyguardTransition() {
         // No display activities never add a window, so there is no point in waiting them for
         // relayout.
-        if (!noDisplay && getDisplayContent() != null) {
-            getDisplayContent().mUnknownAppVisibilityController.notifyLaunched(this);
-        }
-    }
-
-    /**
-     * @return true if the input activity should be made visible, ignoring any effect Keyguard
-     * might have on the visibility
-     *
-     * TODO(b/123540470): Combine this method and {@link #shouldBeVisible(boolean)}.
-     *
-     * @see {@link ActivityStack#checkKeyguardVisibility}
-     */
-    boolean shouldBeVisibleIgnoringKeyguard(boolean behindFullscreenActivity) {
-        if (!okToShowLocked()) {
-            return false;
+        if (noDisplay || !mStackSupervisor.getKeyguardController().isKeyguardLocked()) {
+            return;
         }
 
-        return !behindFullscreenActivity || mLaunchTaskBehind;
+        mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(this);
     }
 
-    boolean shouldBeVisible(boolean behindFullscreenActivity) {
+    /** @return {@code true} if this activity should be made visible. */
+    boolean shouldBeVisible(boolean behindFullscreenActivity, boolean ignoringKeyguard) {
         // Check whether activity should be visible without Keyguard influence
-        visibleIgnoringKeyguard = shouldBeVisibleIgnoringKeyguard(behindFullscreenActivity);
+        visibleIgnoringKeyguard = (!behindFullscreenActivity || mLaunchTaskBehind)
+                && okToShowLocked();
+
+        if (ignoringKeyguard) {
+            return visibleIgnoringKeyguard;
+        }
 
         final ActivityStack stack = getActivityStack();
         if (stack == null) {
@@ -4575,9 +4453,9 @@
             return false;
         }
 
-        // TODO: Use real value of behindFullscreenActivity calculated using the same logic in
-        // ActivityStack#ensureActivitiesVisibleLocked().
-        return shouldBeVisible(!stack.shouldBeVisible(null /* starting */));
+        final boolean behindFullscreenActivity = stack.checkBehindFullscreenActivity(
+                this, null /* handleBehindFullscreenActivity */);
+        return shouldBeVisible(behindFullscreenActivity, false /* ignoringKeyguard */);
     }
 
     void makeVisibleIfNeeded(ActivityRecord starting, boolean reportToClient) {
@@ -4734,16 +4612,25 @@
     }
 
     /**
-     * Check if activity should be moved to RESUMED state. The activity:
-     * - should be eligible to be made active (see {@link #shouldMakeActive(ActivityRecord)})
-     * - should be focusable
+     * Check if activity should be moved to RESUMED state.
+     * See {@link #shouldBeResumed(ActivityRecord)}
      * @param activeActivity the activity that is active or just completed pause action. We won't
      *                       resume if this activity is active.
      */
     @VisibleForTesting
     boolean shouldResumeActivity(ActivityRecord activeActivity) {
-        return shouldMakeActive(activeActivity) && isFocusable() && !isState(RESUMED)
-                && getActivityStack().getVisibility(activeActivity) == STACK_VISIBILITY_VISIBLE;
+        return shouldBeResumed(activeActivity) && !isState(RESUMED);
+    }
+
+    /**
+     * Check if activity should be RESUMED now. The activity:
+     * - should be eligible to be made active (see {@link #shouldMakeActive(ActivityRecord)})
+     * - should be focusable
+     */
+    private boolean shouldBeResumed(ActivityRecord activeActivity) {
+        return shouldMakeActive(activeActivity) && isFocusable()
+                && getActivityStack().getVisibility(activeActivity) == STACK_VISIBILITY_VISIBLE
+                && canResumeByCompat();
     }
 
     /**
@@ -5200,7 +5087,7 @@
         final @LaunchState int launchState = info != null ? info.getLaunchState() : -1;
         mStackSupervisor.reportActivityLaunchedLocked(false /* timeout */, this,
                 windowsDrawnDelayMs, launchState);
-        mStackSupervisor.stopWaitingForActivityVisible(this);
+        mStackSupervisor.stopWaitingForActivityVisible(this, windowsDrawnDelayMs);
         finishLaunchTickingLocked();
         if (task != null) {
             task.hasBeenVisible = true;
@@ -5366,13 +5253,13 @@
         if (!allDrawn && w.mightAffectAllDrawn()) {
             if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) {
                 Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
-                        + ", isAnimationSet=" + isSelfAnimating());
+                        + ", isAnimationSet=" + isAnimating(TRANSITION));
                 if (!w.isDrawnLw()) {
                     Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController
                             + " pv=" + w.isVisibleByPolicy()
                             + " mDrawState=" + winAnimator.drawStateToString()
                             + " ph=" + w.isParentWindowHidden() + " th=" + hiddenRequested
-                            + " a=" + isSelfAnimating());
+                            + " a=" + isAnimating(TRANSITION));
                 }
             }
 
@@ -5396,7 +5283,7 @@
                     }
                 }
             } else if (w.isDrawnLw()) {
-                onStartingWindowDrawn(SystemClock.uptimeMillis());
+                onStartingWindowDrawn(SystemClock.elapsedRealtimeNanos());
                 startingDisplayed = true;
             }
         }
@@ -5405,10 +5292,10 @@
     }
 
     /** Called when the starting window for this container is drawn. */
-    private void onStartingWindowDrawn(long timestamp) {
+    private void onStartingWindowDrawn(long timestampNs) {
         synchronized (mAtmService.mGlobalLock) {
             mAtmService.mStackSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(
-                    getWindowingMode(), timestamp);
+                    getWindowingMode(), timestampNs);
         }
     }
 
@@ -5428,7 +5315,7 @@
             anrActivity = getWaitingHistoryRecordLocked();
             anrApp = app;
             windowFromSameProcessAsActivity =
-                    !hasProcess() || app.getPid() == windowPid || windowPid == -1;
+                    !hasProcess() || app.getPid() == windowPid || windowPid == INVALID_PID;
         }
 
         if (windowFromSameProcessAsActivity) {
@@ -5618,12 +5505,26 @@
         }
     }
 
-    void removeOrphanedStartingWindow(boolean behindFullscreenActivity) {
-        if (mStartingWindowState == STARTING_WINDOW_SHOWN && behindFullscreenActivity) {
+    /**
+     * If any activities below the top running one are in the INITIALIZING state and they have a
+     * starting window displayed then remove that starting window. It is possible that the activity
+     * in this state will never resumed in which case that starting window will be orphaned.
+     * <p>
+     * It should only be called if this activity is behind other fullscreen activity.
+     */
+    void cancelInitializing() {
+        if (mStartingWindowState == STARTING_WINDOW_SHOWN) {
+            // Remove orphaned starting window.
             if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this);
             mStartingWindowState = STARTING_WINDOW_REMOVED;
             removeStartingWindow();
         }
+        if (isState(INITIALIZING) && !shouldBeVisible(
+                true /* behindFullscreenActivity */, true /* ignoringKeyguard */)) {
+            // Remove the unknown visibility record because an invisible activity shouldn't block
+            // the keyguard transition.
+            mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this);
+        }
     }
 
     void postWindowRemoveStartingWindowCleanup(WindowState win) {
@@ -5786,28 +5687,44 @@
         }
     }
 
-
     @VisibleForTesting
     boolean shouldAnimate(int transit) {
+        final Task task = getTask();
+        if (task != null && !task.shouldAnimate()) {
+            return false;
+        }
         final boolean isSplitScreenPrimary =
                 getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
         final boolean allowSplitScreenPrimaryAnimation = transit != TRANSIT_WALLPAPER_OPEN;
 
-        // Don't animate while the task runs recents animation but only if we are in the mode
-        // where we cancel with deferred screenshot, which means that the controller has
-        // transformed the task.
-        final RecentsAnimationController controller = mWmService.getRecentsAnimationController();
-        if (controller != null && controller.isAnimatingTask(getTask())
-                && controller.shouldDeferCancelUntilNextTransition()) {
-            return false;
-        }
-
         // We animate always if it's not split screen primary, and only some special cases in split
         // screen primary because it causes issues with stack clipping when we run an un-minimize
         // animation at the same time.
         return !isSplitScreenPrimary || allowSplitScreenPrimaryAnimation;
     }
 
+    @Override
+    boolean isChangingAppTransition() {
+        final Task task = getTask();
+        if (task != null) {
+            return task.isChangingAppTransition();
+        }
+        return super.isChangingAppTransition();
+    }
+
+    @Override
+    boolean applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
+            boolean isVoiceInteraction) {
+        if (mWmService.mDisableTransitionAnimation || !shouldAnimate(transit)) {
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
+                    "applyAnimation: transition animation is disabled or skipped. "
+                            + "container=%s", this);
+            cancelAnimation();
+            return false;
+        }
+        return super.applyAnimation(lp, transit, enter, isVoiceInteraction);
+    }
+
     /**
      * Creates a layer to apply crop to an animation.
      */
@@ -5821,171 +5738,6 @@
         return boundsLayer;
     }
 
-    boolean applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter,
-            boolean isVoiceInteraction) {
-
-        if (mWmService.mDisableTransitionAnimation || !shouldAnimate(transit)) {
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation: transition animation is disabled or skipped. "
-                            + "atoken=%s", this);
-            cancelAnimation();
-            return false;
-        }
-
-        // Only apply an animation if the display isn't frozen. If it is frozen, there is no reason
-        // to animate and it can cause strange artifacts when we unfreeze the display if some
-        // different animation is running.
-        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AWT#applyAnimationLocked");
-        if (okToAnimate()) {
-            final AnimationAdapter adapter;
-            AnimationAdapter thumbnailAdapter = null;
-
-            final int appStackClipMode =
-                    getDisplayContent().mAppTransition.getAppStackClipMode();
-
-            // Separate position and size for use in animators.
-            mTmpRect.set(getAnimationBounds(appStackClipMode));
-            mTmpPoint.set(mTmpRect.left, mTmpRect.top);
-            mTmpRect.offsetTo(0, 0);
-
-            final boolean isChanging = AppTransition.isChangeTransit(transit) && enter
-                    && getDisplayContent().mChangingApps.contains(this);
-
-            // Delaying animation start isn't compatible with remote animations at all.
-            if (getDisplayContent().mAppTransition.getRemoteAnimationController() != null
-                    && !mSurfaceAnimator.isAnimationStartDelayed()) {
-                RemoteAnimationController.RemoteAnimationRecord adapters =
-                        getDisplayContent().mAppTransition.getRemoteAnimationController()
-                                .createRemoteAnimationRecord(this, mTmpPoint, mTmpRect,
-                                        (isChanging ? mTransitStartRect : null));
-                adapter = adapters.mAdapter;
-                thumbnailAdapter = adapters.mThumbnailAdapter;
-            } else if (isChanging) {
-                final float durationScale = mWmService.getTransitionAnimationScaleLocked();
-                mTmpRect.offsetTo(mTmpPoint.x, mTmpPoint.y);
-                adapter = new LocalAnimationAdapter(
-                        new WindowChangeAnimationSpec(mTransitStartRect, mTmpRect,
-                                getDisplayContent().getDisplayInfo(), durationScale,
-                                true /* isAppAnimation */, false /* isThumbnail */),
-                        mWmService.mSurfaceAnimationRunner);
-                if (mThumbnail != null) {
-                    thumbnailAdapter = new LocalAnimationAdapter(
-                            new WindowChangeAnimationSpec(mTransitStartRect, mTmpRect,
-                                    getDisplayContent().getDisplayInfo(), durationScale,
-                                    true /* isAppAnimation */, true /* isThumbnail */),
-                            mWmService.mSurfaceAnimationRunner);
-                }
-                mTransit = transit;
-                mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
-            } else {
-                mNeedsAnimationBoundsLayer = (appStackClipMode == STACK_CLIP_AFTER_ANIM);
-
-                final Animation a = loadAnimation(lp, transit, enter, isVoiceInteraction);
-                if (a != null) {
-                    // Only apply corner radius to animation if we're not in multi window mode.
-                    // We don't want rounded corners when in pip or split screen.
-                    final float windowCornerRadius = !inMultiWindowMode()
-                            ? getDisplayContent().getWindowCornerRadius()
-                            : 0;
-                    adapter = new LocalAnimationAdapter(
-                            new WindowAnimationSpec(a, mTmpPoint, mTmpRect,
-                                    getDisplayContent().mAppTransition.canSkipFirstFrame(),
-                                    appStackClipMode,
-                                    true /* isAppAnimation */,
-                                    windowCornerRadius),
-                            mWmService.mSurfaceAnimationRunner);
-                    if (a.getZAdjustment() == Animation.ZORDER_TOP) {
-                        mNeedsZBoost = true;
-                    }
-                    mTransit = transit;
-                    mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
-                } else {
-                    adapter = null;
-                }
-            }
-            if (adapter != null) {
-                startAnimation(getPendingTransaction(), adapter, !isVisible());
-                if (adapter.getShowWallpaper()) {
-                    mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
-                }
-                if (thumbnailAdapter != null) {
-                    mThumbnail.startAnimation(
-                            getPendingTransaction(), thumbnailAdapter, !isVisible());
-                }
-            }
-        } else {
-            cancelAnimation();
-        }
-        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
-
-        return isReallyAnimating();
-    }
-
-    private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
-            boolean isVoiceInteraction) {
-        final DisplayContent displayContent = getTask().getDisplayContent();
-        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-        final int width = displayInfo.appWidth;
-        final int height = displayInfo.appHeight;
-        ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                "applyAnimation: atoken=%s", this);
-
-        // Determine the visible rect to calculate the thumbnail clip
-        final WindowState win = findMainWindow();
-        final Rect frame = new Rect(0, 0, width, height);
-        final Rect displayFrame = new Rect(0, 0,
-                displayInfo.logicalWidth, displayInfo.logicalHeight);
-        final Rect insets = new Rect();
-        final Rect stableInsets = new Rect();
-        Rect surfaceInsets = null;
-        final boolean freeform = win != null && win.inFreeformWindowingMode();
-        if (win != null) {
-            // Containing frame will usually cover the whole screen, including dialog windows.
-            // For freeform workspace windows it will not cover the whole screen and it also
-            // won't exactly match the final freeform window frame (e.g. when overlapping with
-            // the status bar). In that case we need to use the final frame.
-            if (freeform) {
-                frame.set(win.getFrameLw());
-            } else if (win.isLetterboxedAppWindow()) {
-                frame.set(getTask().getBounds());
-            } else if (win.isDockedResizing()) {
-                // If we are animating while docked resizing, then use the stack bounds as the
-                // animation target (which will be different than the task bounds)
-                frame.set(getTask().getParent().getBounds());
-            } else {
-                frame.set(win.getContainingFrame());
-            }
-            surfaceInsets = win.getAttrs().surfaceInsets;
-            // XXX(b/72757033): These are insets relative to the window frame, but we're really
-            // interested in the insets relative to the frame we chose in the if-blocks above.
-            win.getContentInsets(insets);
-            win.getStableInsets(stableInsets);
-        }
-
-        if (mLaunchTaskBehind) {
-            // Differentiate the two animations. This one which is briefly on the screen
-            // gets the !enter animation, and the other activity which remains on the
-            // screen gets the enter animation. Both appear in the mOpeningApps set.
-            enter = false;
-        }
-        ProtoLog.d(WM_DEBUG_APP_TRANSITIONS,
-                "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s "
-                        + "surfaceInsets=%s",
-                AppTransition.appTransitionToString(transit), enter, frame, insets, surfaceInsets);
-        final Configuration displayConfig = displayContent.getConfiguration();
-        final Animation a = getDisplayContent().mAppTransition.loadAnimation(lp, transit, enter,
-                displayConfig.uiMode, displayConfig.orientation, frame, displayFrame, insets,
-                surfaceInsets, stableInsets, isVoiceInteraction, freeform, getTask().mTaskId);
-        if (a != null) {
-            if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + this);
-            final int containingWidth = frame.width();
-            final int containingHeight = frame.height();
-            a.initialize(containingWidth, containingHeight, width, height);
-            a.scaleCurrentDuration(mWmService.getTransitionAnimationScaleLocked());
-        }
-        return a;
-    }
-
     @Override
     public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
         return mAnimatingActivityRegistry != null
@@ -6005,6 +5757,7 @@
         return (prevWinMode == WINDOWING_MODE_FREEFORM) != (newWinMode == WINDOWING_MODE_FREEFORM);
     }
 
+    @Override
     boolean isWaitingForTransitionStart() {
         final DisplayContent dc = getDisplayContent();
         // TODO: Test for null can be removed once unification is done.
@@ -6133,10 +5886,7 @@
 
     @Override
     void prepareSurfaces() {
-        // isSelfAnimating also returns true when we are about to start a transition, so we need
-        // to check super here.
-        final boolean reallyAnimating = super.isSelfAnimating();
-        final boolean show = !isHidden() || reallyAnimating;
+        final boolean show = !isHidden() || isAnimating();
 
         if (mSurfaceControl != null) {
             if (show && !mLastSurfaceShowing) {
@@ -6164,14 +5914,13 @@
     }
 
     void attachThumbnailAnimation() {
-        if (!isReallyAnimating()) {
+        if (!isAnimating()) {
             return;
         }
-        final int taskId = getTask().mTaskId;
         final GraphicBuffer thumbnailHeader =
-                getDisplayContent().mAppTransition.getAppTransitionThumbnailHeader(taskId);
+                getDisplayContent().mAppTransition.getAppTransitionThumbnailHeader(getTask());
         if (thumbnailHeader == null) {
-            ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "No thumbnail header bitmap for: %d", taskId);
+            ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "No thumbnail header bitmap for: %s", getTask());
             return;
         }
         clearThumbnail();
@@ -6185,7 +5934,7 @@
      * {@link android.app.ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} animation.
      */
     void attachCrossProfileAppsThumbnailAnimation() {
-        if (!isReallyAnimating()) {
+        if (!isAnimating()) {
             return;
         }
         clearThumbnail();
@@ -6225,22 +5974,11 @@
         final Rect insets = win != null ? win.getContentInsets() : null;
         final Configuration displayConfig = mDisplayContent.getConfiguration();
         return getDisplayContent().mAppTransition.createThumbnailAspectScaleAnimationLocked(
-                appRect, insets, thumbnailHeader, getTask().mTaskId, displayConfig.uiMode,
+                appRect, insets, thumbnailHeader, getTask(), displayConfig.uiMode,
                 displayConfig.orientation);
     }
 
     @Override
-    boolean isAppAnimating() {
-        return isSelfAnimating();
-    }
-
-    @Override
-    boolean isSelfAnimating() {
-        // If we are about to start a transition, we also need to be considered animating.
-        return isWaitingForTransitionStart() || isReallyAnimating();
-    }
-
-    @Override
     public void onAnimationLeashLost(Transaction t) {
         super.onAnimationLeashLost(t);
         if (mAnimationBoundsLayer != null) {
@@ -6345,15 +6083,6 @@
         }
     }
 
-    /**
-     * @return True if and only if we are actually running an animation. Note that
-     *         {@link #isSelfAnimating} also returns true if we are waiting for an animation to
-     *         start.
-     */
-    private boolean isReallyAnimating() {
-        return super.isSelfAnimating();
-    }
-
     @Override
     void cancelAnimation() {
         cancelAnimationOnly();
@@ -6488,7 +6217,7 @@
      *         density or bounds from its parent.
      */
     boolean inSizeCompatMode() {
-        if (!shouldUseSizeCompatMode()) {
+        if (mCompatDisplayInsets == null || !shouldUseSizeCompatMode()) {
             return false;
         }
         final Configuration resolvedConfig = getResolvedOverrideConfiguration();
@@ -6566,58 +6295,54 @@
     }
 
     // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
-    private void updateOverrideConfiguration() {
-        final Configuration overrideConfig = mTmpConfig;
-        overrideConfig.setTo(getRequestedOverrideConfiguration());
-
-        if (shouldUseSizeCompatMode()) {
-            if (mCompatDisplayInsets != null) {
-                // The override configuration is set only once in size compatibility mode.
-                return;
-            }
-            final Configuration parentConfig = getParent().getConfiguration();
-            if (!hasProcess() && !isConfigurationCompatible(parentConfig)) {
-                // Don't compute when launching in fullscreen and the fixed orientation is not the
-                // current orientation. It is more accurately to compute the override bounds from
-                // the updated configuration after the fixed orientation is applied.
-                return;
-            }
-
-            // Ensure the screen related fields are set. It is used to prevent activity relaunch
-            // when moving between displays. For screenWidthDp and screenWidthDp, because they
-            // are relative to bounds and density, they will be calculated in
-            // {@link TaskRecord#computeConfigResourceOverrides} and the result will also be
-            // relatively fixed.
-            overrideConfig.colorMode = parentConfig.colorMode;
-            overrideConfig.densityDpi = parentConfig.densityDpi;
-            overrideConfig.screenLayout = parentConfig.screenLayout
-                    & (Configuration.SCREENLAYOUT_LONG_MASK
-                            | Configuration.SCREENLAYOUT_SIZE_MASK);
-            // The smallest screen width is the short side of screen bounds. Because the bounds
-            // and density won't be changed, smallestScreenWidthDp is also fixed.
-            overrideConfig.smallestScreenWidthDp = parentConfig.smallestScreenWidthDp;
-
-            // The role of CompatDisplayInsets is like the override bounds.
-            final ActivityDisplay display = getDisplay();
-            if (display != null && display.mDisplayContent != null) {
-                mCompatDisplayInsets = new CompatDisplayInsets(display.mDisplayContent);
-            }
-        } else {
-            // We must base this on the parent configuration, because we set our override
-            // configuration's appBounds based on the result of this method. If we used our own
-            // configuration, it would be influenced by past invocations.
-            computeBounds(mTmpBounds, getParent().getWindowConfiguration().getAppBounds());
-
-            if (mTmpBounds.equals(getRequestedOverrideBounds())) {
-                // The bounds is not changed or the activity is resizable (both the 2 bounds are
-                // empty).
-                return;
-            }
-
-            overrideConfig.windowConfiguration.setBounds(mTmpBounds);
+    private void updateSizeCompatMode() {
+        if (mCompatDisplayInsets != null || !shouldUseSizeCompatMode()) {
+            // The override configuration is set only once in size compatibility mode.
+            return;
+        }
+        final Configuration parentConfig = getParent().getConfiguration();
+        if (!hasProcess() && !isConfigurationCompatible(parentConfig)) {
+            // Don't compute when launching in fullscreen and the fixed orientation is not the
+            // current orientation. It is more accurately to compute the override bounds from
+            // the updated configuration after the fixed orientation is applied.
+            return;
         }
 
-        onRequestedOverrideConfigurationChanged(overrideConfig);
+        Configuration overrideConfig = getRequestedOverrideConfiguration();
+        final Configuration fullConfig = getConfiguration();
+
+        // Ensure the screen related fields are set. It is used to prevent activity relaunch
+        // when moving between displays. For screenWidthDp and screenWidthDp, because they
+        // are relative to bounds and density, they will be calculated in
+        // {@link TaskRecord#computeConfigResourceOverrides} and the result will also be
+        // relatively fixed.
+        overrideConfig.colorMode = fullConfig.colorMode;
+        overrideConfig.densityDpi = fullConfig.densityDpi;
+        overrideConfig.screenLayout = fullConfig.screenLayout
+                & (Configuration.SCREENLAYOUT_LONG_MASK
+                        | Configuration.SCREENLAYOUT_SIZE_MASK);
+        // The smallest screen width is the short side of screen bounds. Because the bounds
+        // and density won't be changed, smallestScreenWidthDp is also fixed.
+        overrideConfig.smallestScreenWidthDp = fullConfig.smallestScreenWidthDp;
+        if (info.isFixedOrientation()) {
+            // lock rotation too. When in size-compat, onConfigurationChanged will watch for and
+            // apply runtime rotation changes.
+            overrideConfig.windowConfiguration.setRotation(
+                    fullConfig.windowConfiguration.getRotation());
+        }
+
+        // The role of CompatDisplayInsets is like the override bounds.
+        final ActivityDisplay display = getDisplay();
+        if (display != null) {
+            mCompatDisplayInsets = new CompatDisplayInsets(display.mDisplayContent,
+                    getWindowConfiguration().getBounds(),
+                    getWindowConfiguration().tasksAreFloating());
+        }
+    }
+
+    private void clearSizeCompatMode() {
+        mCompatDisplayInsets = null;
+        onRequestedOverrideConfigurationChanged(EMPTY);
     }
 
     @Override
@@ -6638,13 +6363,17 @@
 
     @Override
     void resolveOverrideConfiguration(Configuration newParentConfiguration) {
+        Configuration resolvedConfig = getResolvedOverrideConfiguration();
         if (mCompatDisplayInsets != null) {
             resolveSizeCompatModeConfiguration(newParentConfiguration);
         } else {
             super.resolveOverrideConfiguration(newParentConfiguration);
+            applyAspectRatio(resolvedConfig.windowConfiguration.getBounds(),
+                    newParentConfiguration.windowConfiguration.getAppBounds(),
+                    newParentConfiguration.windowConfiguration.getBounds());
             // If the activity has override bounds, the relative configuration (e.g. screen size,
             // layout) needs to be resolved according to the bounds.
-            if (task != null && !matchParentBounds()) {
+            if (task != null && !resolvedConfig.windowConfiguration.getBounds().isEmpty()) {
                 task.computeConfigResourceOverrides(getResolvedOverrideConfiguration(),
                         newParentConfiguration);
             }
@@ -6662,82 +6391,71 @@
      * inheriting the parent bounds.
      */
     private void resolveSizeCompatModeConfiguration(Configuration newParentConfiguration) {
+        super.resolveOverrideConfiguration(newParentConfiguration);
         final Configuration resolvedConfig = getResolvedOverrideConfiguration();
         final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
 
-        final int parentRotation = newParentConfiguration.windowConfiguration.getRotation();
-        final int parentOrientation = newParentConfiguration.orientation;
-        int orientation = getConfiguration().orientation;
-        if (orientation != parentOrientation && isConfigurationCompatible(newParentConfiguration)) {
-            // The activity is compatible to apply the orientation change or it requests different
-            // fixed orientation.
-            orientation = parentOrientation;
-        } else {
-            if (!resolvedBounds.isEmpty()
-                    // The decor insets may be different according to the rotation.
-                    && getWindowConfiguration().getRotation() == parentRotation) {
-                // Keep the computed resolved override configuration.
-                return;
-            }
-            final int requestedOrientation = getRequestedConfigurationOrientation();
-            if (requestedOrientation != ORIENTATION_UNDEFINED) {
-                orientation = requestedOrientation;
-            }
+        Rect parentBounds = new Rect(newParentConfiguration.windowConfiguration.getBounds());
+
+        int orientation = getRequestedConfigurationOrientation();
+        if (orientation == ORIENTATION_UNDEFINED) {
+            orientation = newParentConfiguration.orientation;
+        }
+        int rotation = resolvedConfig.windowConfiguration.getRotation();
+        if (rotation == ROTATION_UNDEFINED) {
+            rotation = newParentConfiguration.windowConfiguration.getRotation();
         }
 
-        super.resolveOverrideConfiguration(newParentConfiguration);
-
-        boolean useParentOverrideBounds = false;
-        final Rect displayBounds = mTmpBounds;
+        // Use compat insets to lock width and height. We should not use the parent width and height
+        // because apps in compat mode should have a constant width and height. The compat insets
+        // are locked when the app is first launched and are never changed after that, so we can
+        // rely on them to contain the original and unchanging width and height of the app.
+        final Rect compatDisplayBounds = mTmpBounds;
+        mCompatDisplayInsets.getDisplayBoundsByRotation(compatDisplayBounds, rotation);
         final Rect containingAppBounds = new Rect();
-        if (task.handlesOrientationChangeFromDescendant()) {
-            // Prefer to use the orientation which is determined by this activity to calculate
-            // bounds because the parent will follow the requested orientation.
-            mCompatDisplayInsets.getDisplayBoundsByOrientation(displayBounds, orientation);
-        } else {
-            // The parent hierarchy doesn't handle the orientation changes. This is usually because
-            // the aspect ratio of display is close to square or the display rotation is fixed.
-            // In this case, task will compute override bounds to fit the app with respect to the
-            // requested orientation. So here we perform similar calculation to have consistent
-            // bounds even the original parent hierarchies were changed.
-            final int baseOrientation = task.getParent().getConfiguration().orientation;
-            mCompatDisplayInsets.getDisplayBoundsByOrientation(displayBounds, baseOrientation);
-            task.computeFullscreenBounds(containingAppBounds, this, displayBounds, baseOrientation);
-            useParentOverrideBounds = !containingAppBounds.isEmpty();
+        mCompatDisplayInsets.getFrameByOrientation(containingAppBounds, orientation);
+
+        // Center containingAppBounds horizontally and aligned to top of parent. Both
+        // are usually the same unless the app was frozen with an orientation letterbox.
+        int left = compatDisplayBounds.left + compatDisplayBounds.width() / 2
+                - containingAppBounds.width() / 2;
+        resolvedBounds.set(left, compatDisplayBounds.top, left + containingAppBounds.width(),
+                compatDisplayBounds.top + containingAppBounds.height());
+
+        if (rotation != ROTATION_UNDEFINED) {
+            // Ensure the parent and container bounds won't overlap with insets.
+            TaskRecord.intersectWithInsetsIfFits(containingAppBounds, compatDisplayBounds,
+                    mCompatDisplayInsets.mNonDecorInsets[rotation]);
+            TaskRecord.intersectWithInsetsIfFits(parentBounds, compatDisplayBounds,
+                    mCompatDisplayInsets.mNonDecorInsets[rotation]);
         }
 
-        // The offsets will be non-zero if the parent has override bounds.
-        final int containingOffsetX = containingAppBounds.left;
-        final int containingOffsetY = containingAppBounds.top;
-        if (!useParentOverrideBounds) {
-            containingAppBounds.set(displayBounds);
-        }
-        if (parentRotation != ROTATION_UNDEFINED) {
-            // Ensure the container bounds won't overlap with the decors.
-            TaskRecord.intersectWithInsetsIfFits(containingAppBounds, displayBounds,
-                    mCompatDisplayInsets.mNonDecorInsets[parentRotation]);
-        }
+        applyAspectRatio(resolvedBounds, containingAppBounds, compatDisplayBounds);
 
-        computeBounds(resolvedBounds, containingAppBounds);
-        if (resolvedBounds.isEmpty()) {
-            // Use the entire available bounds because there is no restriction.
-            resolvedBounds.set(useParentOverrideBounds ? containingAppBounds : displayBounds);
-        } else {
-            // The offsets are included in width and height by {@link #computeBounds}, so we have to
-            // restore it.
-            resolvedBounds.left += containingOffsetX;
-            resolvedBounds.top += containingOffsetY;
-        }
+        // Center horizontally in parent and align to top of parent - this is a UX choice
+        left = parentBounds.left + parentBounds.width() / 2 - resolvedBounds.width() / 2;
+        resolvedBounds.set(left, parentBounds.top, left + resolvedBounds.width(),
+                parentBounds.top + resolvedBounds.height());
+
+        // We want to get as much of the app on the screen even if insets cover it. This is because
+        // insets change but an app's bounds are more permanent after launch. After computing insets
+        // and horizontally centering resolvedBounds, the resolvedBounds may end up outside parent
+        // bounds. This is okay only if the resolvedBounds exceed their parent on the bottom and
+        // right, because that is clipped when the final bounds are computed. To reach this state,
+        // we first try and push the app as much inside the parent towards the top and left (the
+        // min). The app may then end up outside the parent by going too far left and top, so we
+        // push it back into the parent by taking the max with parent left and top.
+        Rect fullParentBounds = newParentConfiguration.windowConfiguration.getBounds();
+        resolvedBounds.offsetTo(Math.max(fullParentBounds.left,
+                Math.min(fullParentBounds.right - resolvedBounds.width(), resolvedBounds.left)),
+                Math.max(fullParentBounds.top,
+                        Math.min(fullParentBounds.bottom - resolvedBounds.height(),
+                                resolvedBounds.top)));
+
+        // Use resolvedBounds to compute other override configurations such as appBounds
         task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
                 mCompatDisplayInsets);
 
-        // The horizontal inset included in width is not needed if the activity cannot fill the
-        // parent, because the offset will be applied by {@link ActivityRecord#mSizeCompatBounds}.
-        final Rect resolvedAppBounds = resolvedConfig.windowConfiguration.getAppBounds();
-        final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds();
-        if (resolvedBounds.width() < parentAppBounds.width()) {
-            resolvedBounds.right -= resolvedAppBounds.left;
-        }
         // Use parent orientation if it cannot be decided by bounds, so the activity can fit inside
         // the parent bounds appropriately.
         if (resolvedConfig.screenWidthDp == resolvedConfig.screenHeightDp) {
@@ -6766,6 +6484,7 @@
     }
 
     @VisibleForTesting
+    @Override
     Rect getAnimationBounds(int appStackClipMode) {
         if (appStackClipMode == STACK_CLIP_BEFORE_ANIM && getStack() != null) {
             // Using the stack bounds here effectively applies the clipping before animation.
@@ -6812,6 +6531,33 @@
 
     @Override
     public void onConfigurationChanged(Configuration newParentConfig) {
+        if (mCompatDisplayInsets != null) {
+            Configuration overrideConfig = getRequestedOverrideConfiguration();
+            // Adapt to changes in orientation locking. The app is still non-resizable, but
+            // it can change which orientation is fixed. If the fixed orientation changes,
+            // update the rotation used on the "compat" display
+            boolean wasFixedOrient =
+                    overrideConfig.windowConfiguration.getRotation() != ROTATION_UNDEFINED;
+            int requestedOrient = getRequestedConfigurationOrientation();
+            if (requestedOrient != ORIENTATION_UNDEFINED
+                    && requestedOrient != getConfiguration().orientation
+                    // The task orientation depends on the top activity orientation, so it
+                    // should match. If it doesn't, just wait until it does.
+                    && requestedOrient == getParent().getConfiguration().orientation
+                    && (overrideConfig.windowConfiguration.getRotation()
+                            != getParent().getWindowConfiguration().getRotation())) {
+                overrideConfig.windowConfiguration.setRotation(
+                        getParent().getWindowConfiguration().getRotation());
+                onRequestedOverrideConfigurationChanged(overrideConfig);
+                return;
+            } else if (wasFixedOrient && requestedOrient == ORIENTATION_UNDEFINED
+                    && (overrideConfig.windowConfiguration.getRotation()
+                            != ROTATION_UNDEFINED)) {
+                overrideConfig.windowConfiguration.setRotation(ROTATION_UNDEFINED);
+                onRequestedOverrideConfigurationChanged(overrideConfig);
+                return;
+            }
+        }
         final int prevWinMode = getWindowingMode();
         mTmpPrevBounds.set(getBounds());
         super.onConfigurationChanged(newParentConfig);
@@ -6836,6 +6582,10 @@
                 mSizeCompatScale = 1f;
                 updateSurfacePosition();
             }
+        } else if (overrideBounds.isEmpty()) {
+            mSizeCompatBounds = null;
+            mSizeCompatScale = 1f;
+            updateSurfacePosition();
         }
 
         adjustPinnedStackAndInitChangeTransitionIfNeeded(prevWinMode, getWindowingMode());
@@ -6854,7 +6604,7 @@
         if (visible) {
             // It may toggle the UI for user to restart the size compatibility mode activity.
             display.handleActivitySizeCompatModeIfNeeded(this);
-        } else if (shouldUseSizeCompatMode()) {
+        } else if (mCompatDisplayInsets != null) {
             // The override changes can only be obtained from display, because we don't have the
             // difference of full configuration in each hierarchy.
             final int displayChanges = display.getLastOverrideConfigurationChanges();
@@ -6918,22 +6668,21 @@
     }
 
     /**
-     * Computes the bounds to fit the Activity within the bounds of the {@link Configuration}.
+     * Applies aspect ratio restrictions to outBounds. If no restrictions, then no change is
+     * made to outBounds.
      */
     // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
-    private void computeBounds(Rect outBounds, Rect containingAppBounds) {
-        outBounds.setEmpty();
+    private void applyAspectRatio(Rect outBounds, Rect containingAppBounds,
+            Rect containingBounds) {
         final float maxAspectRatio = info.maxAspectRatio;
         final ActivityStack stack = getActivityStack();
         final float minAspectRatio = info.minAspectRatio;
 
-        if (task == null || stack == null || task.inMultiWindowMode()
+        if (task == null || stack == null || (inMultiWindowMode() && !shouldUseSizeCompatMode())
                 || (maxAspectRatio == 0 && minAspectRatio == 0)
                 || isInVrUiMode(getConfiguration())) {
-            // We don't set override configuration if that activity task isn't fullscreen. I.e. the
-            // activity is in multi-window mode. Or, there isn't a max aspect ratio specified for
-            // the activity. This is indicated by an empty {@link outBounds}. We also don't set it
-            // if we are in VR mode.
+            // We don't enforce aspect ratio if the activity task is in multiwindow unless it
+            // is in size-compat mode. We also don't set it if we are in VR mode.
             return;
         }
 
@@ -6991,12 +6740,6 @@
 
         if (containingAppWidth <= activityWidth && containingAppHeight <= activityHeight) {
             // The display matches or is less than the activity aspect ratio, so nothing else to do.
-            // Return the existing bounds. If this method is running for the first time,
-            // {@link #getRequestedOverrideBounds()} will be empty (representing no override). If
-            // the method has run before, then effect of {@link #getRequestedOverrideBounds()} will
-            // already have been applied to the value returned from {@link getConfiguration}. Refer
-            // to {@link TaskRecord#computeConfigResourceOverrides()}.
-            outBounds.set(getRequestedOverrideBounds());
             return;
         }
 
@@ -7004,7 +6747,8 @@
         // Also account for the left / top insets (e.g. from display cutouts), which will be clipped
         // away later in {@link TaskRecord#computeConfigResourceOverrides()}. Otherwise, the app
         // bounds would end up too small.
-        outBounds.set(0, 0, activityWidth + containingAppBounds.left,
+        outBounds.set(containingBounds.left, containingBounds.top,
+                activityWidth + containingAppBounds.left,
                 activityHeight + containingAppBounds.top);
     }
 
@@ -7067,7 +6811,7 @@
             mLastReportedDisplayId = newDisplayId;
         }
         // TODO(b/36505427): Is there a better place to do this?
-        updateOverrideConfiguration();
+        updateSizeCompatMode();
 
         // Short circuit: if the two full configurations are equal (the common case), then there is
         // nothing to do.  We test the full configuration instead of the global and merged override
@@ -7162,23 +6906,14 @@
                 deferRelaunchUntilPaused = true;
                 preserveWindowOnDeferredRelaunch = preserveWindow;
                 return true;
-            } else if (mState == RESUMED) {
-                // Try to optimize this case: the configuration is changing and we need to restart
-                // the top, resumed activity. Instead of doing the normal handshaking, just say
-                // "restart!".
-                if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                        "Config is relaunching resumed " + this);
-
-                if (DEBUG_STATES && !visible) {
-                    Slog.v(TAG_STATES, "Config is relaunching resumed invisible activity " + this
-                            + " called by " + Debug.getCallers(4));
-                }
-
-                relaunchActivityLocked(true /* andResume */, preserveWindow);
             } else {
                 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                        "Config is relaunching non-resumed " + this);
-                relaunchActivityLocked(false /* andResume */, preserveWindow);
+                        "Config is relaunching " + this);
+                if (DEBUG_STATES && !visible) {
+                    Slog.v(TAG_STATES, "Config is relaunching invisible activity " + this
+                            + " called by " + Debug.getCallers(4));
+                }
+                relaunchActivityLocked(preserveWindow);
             }
 
             // All done...  tell the caller we weren't able to keep this activity around.
@@ -7276,12 +7011,13 @@
                 | CONFIG_SCREEN_LAYOUT)) != 0;
     }
 
-    void relaunchActivityLocked(boolean andResume, boolean preserveWindow) {
+    void relaunchActivityLocked(boolean preserveWindow) {
         if (mAtmService.mSuppressResizeConfigChanges && preserveWindow) {
             configChangeFlags = 0;
             return;
         }
 
+        final boolean andResume = shouldBeResumed(null /*activeActivity*/);
         List<ResultInfo> pendingResults = null;
         List<ReferrerIntent> pendingNewIntents = null;
         if (andResume) {
@@ -7358,13 +7094,11 @@
 
         // Reset the existing override configuration so it can be updated according to the latest
         // configuration.
-        getRequestedOverrideConfiguration().unset();
-        getResolvedOverrideConfiguration().unset();
-        mCompatDisplayInsets = null;
+        clearSizeCompatMode();
         if (visible) {
             // Configuration will be ensured when becoming visible, so if it is already visible,
             // then the manual update is needed.
-            updateOverrideConfiguration();
+            updateSizeCompatMode();
         }
 
         if (!attachedToProcess()) {
@@ -7695,7 +7429,7 @@
         super.writeToProto(proto, WINDOW_TOKEN, logLevel);
         proto.write(LAST_SURFACE_SHOWING, mLastSurfaceShowing);
         proto.write(IS_WAITING_FOR_TRANSITION_START, isWaitingForTransitionStart());
-        proto.write(IS_REALLY_ANIMATING, isReallyAnimating());
+        proto.write(IS_ANIMATING, isAnimating());
         if (mThumbnail != null){
             mThumbnail.writeToProto(proto, THUMBNAIL);
         }
@@ -7743,8 +7477,10 @@
      * compatibility mode activity compute the configuration without relying on its current display.
      */
     static class CompatDisplayInsets {
-        final int mDisplayWidth;
-        final int mDisplayHeight;
+        private final int mDisplayWidth;
+        private final int mDisplayHeight;
+        private final int mWidth;
+        private final int mHeight;
 
         /**
          * The nonDecorInsets for each rotation. Includes the navigation bar and cutout insets. It
@@ -7758,9 +7494,23 @@
          */
         final Rect[] mStableInsets = new Rect[4];
 
-        CompatDisplayInsets(DisplayContent display) {
+        /**
+         * Sets bounds to {@link TaskRecord} bounds. For apps in freeform, the task bounds are the
+         * parent bounds from the app's perspective. No insets because within a window.
+         */
+        CompatDisplayInsets(DisplayContent display, Rect activityBounds, boolean isFloating) {
             mDisplayWidth = display.mBaseDisplayWidth;
             mDisplayHeight = display.mBaseDisplayHeight;
+            mWidth = activityBounds.width();
+            mHeight = activityBounds.height();
+            if (isFloating) {
+                Rect emptyRect = new Rect();
+                for (int rotation = 0; rotation < 4; rotation++) {
+                    mNonDecorInsets[rotation] = emptyRect;
+                    mStableInsets[rotation] = emptyRect;
+                }
+                return;
+            }
             final DisplayPolicy policy = display.getDisplayPolicy();
             for (int rotation = 0; rotation < 4; rotation++) {
                 mNonDecorInsets[rotation] = new Rect();
@@ -7783,9 +7533,9 @@
             outBounds.set(0, 0, dw, dh);
         }
 
-        void getDisplayBoundsByOrientation(Rect outBounds, int orientation) {
-            final int longSide = Math.max(mDisplayWidth, mDisplayHeight);
-            final int shortSide = Math.min(mDisplayWidth, mDisplayHeight);
+        void getFrameByOrientation(Rect outBounds, int orientation) {
+            final int longSide = Math.max(mWidth, mHeight);
+            final int shortSide = Math.min(mWidth, mHeight);
             final boolean isLandscape = orientation == ORIENTATION_LANDSCAPE;
             outBounds.set(0, 0, isLandscape ? longSide : shortSide,
                     isLandscape ? shortSide : longSide);
@@ -7801,4 +7551,35 @@
             System.arraycopy(translation, 0, mTranslation, 0, mTranslation.length);
         }
     }
+
+    @Override
+    RemoteAnimationTarget createRemoteAnimationTarget(
+            RemoteAnimationController.RemoteAnimationRecord record) {
+        final Task task = getTask();
+        final WindowState mainWindow = findMainWindow();
+        if (task == null || mainWindow == null) {
+            return null;
+        }
+        final Rect insets = new Rect();
+        mainWindow.getContentInsets(insets);
+        InsetUtils.addInsets(insets, getLetterboxInsets());
+        return new RemoteAnimationTarget(task.mTaskId, record.getMode(),
+                record.mAdapter.mCapturedLeash, !task.fillsParent(),
+                mainWindow.mWinAnimator.mLastClipRect, insets,
+                getPrefixOrderIndex(), record.mAdapter.mPosition,
+                record.mAdapter.mStackBounds, task.getWindowConfiguration(),
+                false /*isNotInRecents*/,
+                record.mThumbnailAdapter != null ? record.mThumbnailAdapter.mCapturedLeash : null,
+                record.mStartBounds);
+    }
+
+    @Override
+    void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
+            Rect outSurfaceInsets) {
+        final WindowState win = findMainWindow();
+        if (win == null) {
+            return;
+        }
+        win.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
+    }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 41c1e4e..edf8789 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -162,6 +162,7 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.function.Consumer;
 
 /**
  * State and management of a single stack of activities.
@@ -246,12 +247,13 @@
         ActivityDisplay current = getParent();
         if (current != parent) {
             mDisplayId = parent.mDisplayId;
-            onParentChanged();
+            onParentChanged(parent, current);
         }
     }
 
     @Override
-    protected void onParentChanged() {
+    protected void onParentChanged(
+            ConfigurationContainer newParent, ConfigurationContainer oldParent) {
         ActivityDisplay display = getParent();
         if (display != null) {
             // Rotations are relative to the display. This means if there are 2 displays rotated
@@ -264,7 +266,7 @@
             getConfiguration().windowConfiguration.setRotation(
                     display.getWindowConfiguration().getRotation());
         }
-        super.onParentChanged();
+        super.onParentChanged(newParent, oldParent);
         if (display != null && inSplitScreenPrimaryWindowingMode()) {
             // If we created a docked stack we want to resize it so it resizes all other stacks
             // in the system.
@@ -915,12 +917,13 @@
 
     /** Removes the stack completely. Also calls WindowManager to do the same on its side. */
     void remove() {
+        final ActivityDisplay oldDisplay = getDisplay();
         removeFromDisplay();
         if (mTaskStack != null) {
             mTaskStack.removeIfPossible();
             mTaskStack = null;
         }
-        onParentChanged();
+        onParentChanged(null, oldDisplay);
     }
 
     ActivityDisplay getDisplay() {
@@ -1789,8 +1792,7 @@
                 if (prev.deferRelaunchUntilPaused) {
                     // Complete the deferred relaunch that was waiting for pause to complete.
                     if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Re-launching after pause: " + prev);
-                    prev.relaunchActivityLocked(false /* andResume */,
-                            prev.preserveWindowOnDeferredRelaunch);
+                    prev.relaunchActivityLocked(prev.preserveWindowOnDeferredRelaunch);
                 } else if (wasStopping) {
                     // We are also stopping, the stop request must have gone soon after the pause.
                     // We can't clobber it, because the stop confirmation will not be handled.
@@ -2116,14 +2118,21 @@
                     }
                     aboveTop = false;
 
+                    final boolean reallyVisible = r.shouldBeVisible(behindFullscreenActivity,
+                            false /* ignoringKeyguard */);
                     // Check whether activity should be visible without Keyguard influence
-                    final boolean visibleIgnoringKeyguard = r.shouldBeVisibleIgnoringKeyguard(
-                            behindFullscreenActivity);
-                    final boolean reallyVisible = r.shouldBeVisible(behindFullscreenActivity);
-                    if (visibleIgnoringKeyguard) {
-                        behindFullscreenActivity = updateBehindFullscreen(!stackShouldBeVisible,
-                                behindFullscreenActivity, r);
+                    if (r.visibleIgnoringKeyguard) {
+                        if (r.occludesParent()) {
+                            // At this point, nothing else needs to be shown in this task.
+                            if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Fullscreen: at " + r
+                                    + " stackVisible=" + stackShouldBeVisible
+                                    + " behindFullscreen=" + behindFullscreenActivity);
+                            behindFullscreenActivity = true;
+                        } else {
+                            behindFullscreenActivity = false;
+                        }
                     }
+
                     if (reallyVisible) {
                         if (r.finishing) {
                             continue;
@@ -2336,18 +2345,6 @@
         return false;
     }
 
-    private boolean updateBehindFullscreen(boolean stackInvisible, boolean behindFullscreenActivity,
-            ActivityRecord r) {
-        if (r.occludesParent()) {
-            if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Fullscreen: at " + r
-                        + " stackInvisible=" + stackInvisible
-                        + " behindFullscreenActivity=" + behindFullscreenActivity);
-            // At this point, nothing else needs to be shown in this task.
-            behindFullscreenActivity = true;
-        }
-        return behindFullscreenActivity;
-    }
-
     void convertActivityToTranslucent(ActivityRecord r) {
         mTranslucentActivityWaiting = r;
         mUndrawnActivitiesBelowTopTranslucent.clear();
@@ -2398,14 +2395,22 @@
         }
     }
 
-    /** If any activities below the top running one are in the INITIALIZING state and they have a
-     * starting window displayed then remove that starting window. It is possible that the activity
-     * in this state will never resumed in which case that starting window will be orphaned. */
+    /** @see ActivityRecord#cancelInitializing() */
     void cancelInitializingActivities() {
-        final ActivityRecord topActivity = topRunningActivityLocked();
-        boolean aboveTop = true;
         // We don't want to clear starting window for activities that aren't behind fullscreen
         // activities as we need to display their starting window until they are done initializing.
+        checkBehindFullscreenActivity(null /* toCheck */, ActivityRecord::cancelInitializing);
+    }
+
+    /**
+     * If an activity {@param toCheck} is given, this method returns {@code true} if the activity
+     * is occluded by any fullscreen activity. If there is no {@param toCheck} and the handling
+     * function {@param handleBehindFullscreenActivity} is given, this method will pass all occluded
+     * activities to the function.
+     */
+    boolean checkBehindFullscreenActivity(ActivityRecord toCheck,
+            Consumer<ActivityRecord> handleBehindFullscreenActivity) {
+        boolean aboveTop = true;
         boolean behindFullscreenActivity = false;
 
         if (!shouldBeVisible(null)) {
@@ -2415,22 +2420,40 @@
             behindFullscreenActivity = true;
         }
 
+        final boolean handlingOccluded = toCheck == null && handleBehindFullscreenActivity != null;
+        if (!handlingOccluded && behindFullscreenActivity) {
+            return true;
+        }
+
+        final ActivityRecord topActivity = topRunningActivityLocked();
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
             for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = task.getChildAt(activityNdx);
                 if (aboveTop) {
                     if (r == topActivity) {
+                        if (r == toCheck) {
+                            // It is the top activity in a visible stack.
+                            return false;
+                        }
                         aboveTop = false;
                     }
                     behindFullscreenActivity |= r.occludesParent();
                     continue;
                 }
 
-                r.removeOrphanedStartingWindow(behindFullscreenActivity);
+                if (handlingOccluded) {
+                    handleBehindFullscreenActivity.accept(r);
+                } else if (r == toCheck) {
+                    return behindFullscreenActivity;
+                } else if (behindFullscreenActivity) {
+                    // It is occluded before {@param toCheck} is found.
+                    return true;
+                }
                 behindFullscreenActivity |= r.occludesParent();
             }
         }
+        return behindFullscreenActivity;
     }
 
     /**
@@ -4719,12 +4742,13 @@
      *             {@link #REMOVE_TASK_MODE_MOVING}, {@link #REMOVE_TASK_MODE_MOVING_TO_TOP}.
      */
     void removeTask(TaskRecord task, String reason, int mode) {
-        final boolean removed = mTaskHistory.remove(task);
-
-        if (removed) {
-            EventLog.writeEvent(EventLogTags.AM_REMOVE_TASK, task.mTaskId, getStackId());
+        if (!mTaskHistory.remove(task)) {
+            // Not really in this stack anymore...
+            return;
         }
 
+        EventLog.writeEvent(EventLogTags.AM_REMOVE_TASK, task.mTaskId, getStackId());
+
         removeActivitiesFromLRUList(task);
         updateTaskMovement(task, true);
 
@@ -4758,7 +4782,7 @@
         if (inPinnedWindowingMode()) {
             mService.getTaskChangeNotificationController().notifyActivityUnpinned();
         }
-        if (display.isSingleTaskInstance()) {
+        if (display != null && display.isSingleTaskInstance()) {
             mService.notifySingleTaskDisplayEmpty(display.mDisplayId);
         }
     }
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 887ece5..dc3d263 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -82,6 +82,7 @@
 import static com.android.server.wm.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
 import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
 import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 
 import android.Manifest;
 import android.app.Activity;
@@ -561,8 +562,8 @@
         return candidateTaskId;
     }
 
-    void waitActivityVisible(ComponentName name, WaitResult result, long startTimeMs) {
-        final WaitInfo waitInfo = new WaitInfo(name, result, startTimeMs);
+    void waitActivityVisible(ComponentName name, WaitResult result) {
+        final WaitInfo waitInfo = new WaitInfo(name, result);
         mWaitingForActivityVisible.add(waitInfo);
     }
 
@@ -572,10 +573,15 @@
         // down to the max limit while they are still waiting to finish.
         mFinishingActivities.remove(r);
 
-        stopWaitingForActivityVisible(r);
+        stopWaitingForActivityVisible(r, WaitResult.INVALID_DELAY);
     }
 
     void stopWaitingForActivityVisible(ActivityRecord r) {
+        stopWaitingForActivityVisible(r,
+                getActivityMetricsLogger().getLastDrawnDelayMs(r.getWindowingMode()));
+    }
+
+    void stopWaitingForActivityVisible(ActivityRecord r, long totalTime) {
         boolean changed = false;
         for (int i = mWaitingForActivityVisible.size() - 1; i >= 0; --i) {
             final WaitInfo w = mWaitingForActivityVisible.get(i);
@@ -584,7 +590,7 @@
                 changed = true;
                 result.timeout = false;
                 result.who = w.getComponent();
-                result.totalTime = SystemClock.uptimeMillis() - w.getStartTime();
+                result.totalTime = totalTime;
                 mWaitingForActivityVisible.remove(w);
             }
         }
@@ -752,9 +758,7 @@
                 andResume = false;
             }
 
-            if (getKeyguardController().isKeyguardLocked()) {
-                r.notifyUnknownVisibilityLaunched();
-            }
+            r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
 
             // Have the window manager re-evaluate the orientation of the screen based on the new
             // activity order.  Note that as a result of this, it can call back into the activity
@@ -992,12 +996,7 @@
             knownToBeDead = true;
         }
 
-        // Suppress transition until the new activity becomes ready, otherwise the keyguard can
-        // appear for a short amount of time before the new process with the new activity had the
-        // ability to set its showWhenLocked flags.
-        if (getKeyguardController().isKeyguardLocked()) {
-            r.notifyUnknownVisibilityLaunched();
-        }
+        r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
 
         final boolean isTop = andResume && r.isTopRunningActivity();
         mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
@@ -2134,7 +2133,7 @@
         for (int activityNdx = mStoppingActivities.size() - 1; activityNdx >= 0; --activityNdx) {
             ActivityRecord s = mStoppingActivities.get(activityNdx);
 
-            final boolean animating = s.isSelfAnimating();
+            final boolean animating = s.isAnimating(TRANSITION);
 
             if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + nowVisible
                     + " animating=" + animating + " finishing=" + s.finishing);
@@ -2247,7 +2246,7 @@
                     // Complete + brief == give a summary.  Isn't that obvious?!?
                     if (lastTask.intent != null) {
                         pw.print(prefix); pw.print("  ");
-                                pw.println(lastTask.intent.toInsecureStringWithClip());
+                                pw.println(lastTask.intent.toInsecureString());
                     }
                 }
             }
@@ -2830,13 +2829,10 @@
     static class WaitInfo {
         private final ComponentName mTargetComponent;
         private final WaitResult mResult;
-        /** Time stamp when we started to wait for {@link WaitResult}. */
-        private final long mStartTimeMs;
 
-        WaitInfo(ComponentName targetComponent, WaitResult result, long startTimeMs) {
+        WaitInfo(ComponentName targetComponent, WaitResult result) {
             this.mTargetComponent = targetComponent;
             this.mResult = result;
-            this.mStartTimeMs = startTimeMs;
         }
 
         public boolean matches(ComponentName targetComponent) {
@@ -2847,10 +2843,6 @@
             return mResult;
         }
 
-        public long getStartTime() {
-            return mStartTimeMs;
-        }
-
         public ComponentName getComponent() {
             return mTargetComponent;
         }
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 63cec1a..2c4d893 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -284,7 +284,7 @@
                 .setRequestCode(requestCode)
                 .setStartFlags(startFlags)
                 .setActivityOptions(options)
-                .setMayWait(userId)
+                .setUserId(userId)
                 .setInTask(inTask)
                 .setOriginatingPendingIntent(originatingPendingIntent)
                 .setAllowBackgroundActivityStart(allowBackgroundActivityStart)
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 2ac681c..d1bb255 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -107,7 +107,6 @@
 import android.os.IBinder;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -199,7 +198,7 @@
     private IVoiceInteractor mVoiceInteractor;
 
     // Last activity record we attempted to start
-    private final ActivityRecord[] mLastStartActivityRecord = new ActivityRecord[1];
+    private ActivityRecord mLastStartActivityRecord;
     // The result of the last activity we attempted to start.
     private int mLastStartActivityResult;
     // Time in milli seconds we attempted to start the last activity.
@@ -212,7 +211,8 @@
      * to avoid unnecessarily retaining parameters. Note that the request is ignored when
      * {@link #startResolvedActivity} is invoked directly.
      */
-    private Request mRequest = new Request();
+    @VisibleForTesting
+    Request mRequest = new Request();
 
     /**
      * An interface that to provide {@link ActivityStarter} instances to the controller. This is
@@ -299,7 +299,8 @@
      * {@link #dump(PrintWriter, String)} and therefore cannot be cleared immediately after
      * execution.
      */
-    private static class Request {
+    @VisibleForTesting
+    static class Request {
         private static final int DEFAULT_CALLING_UID = -1;
         private static final int DEFAULT_CALLING_PID = 0;
         static final int DEFAULT_REAL_CALLING_UID = -1;
@@ -307,6 +308,7 @@
 
         IApplicationThread caller;
         Intent intent;
+        // A copy of the original requested intent, in case for ephemeral app launch.
         Intent ephemeralIntent;
         String resolvedType;
         ActivityInfo activityInfo;
@@ -344,13 +346,6 @@
         boolean allowPendingRemoteAnimationRegistryLookup;
 
         /**
-         * Indicates that we should wait for the result of the start request. This flag is set when
-         * {@link ActivityStarter#setMayWait(int)} is called.
-         * {@see ActivityStarter#startActivityMayWait}.
-         */
-        boolean mayWait;
-
-        /**
          * Ensure constructed request matches reset instance.
          */
         Request() {
@@ -388,7 +383,6 @@
             globalConfig = null;
             userId = 0;
             waitResult = null;
-            mayWait = false;
             avoidMoveToFront = false;
             allowPendingRemoteAnimationRegistryLookup = true;
             filterCallingUid = UserHandle.USER_NULL;
@@ -427,7 +421,6 @@
             globalConfig = request.globalConfig;
             userId = request.userId;
             waitResult = request.waitResult;
-            mayWait = request.mayWait;
             avoidMoveToFront = request.avoidMoveToFront;
             allowPendingRemoteAnimationRegistryLookup
                     = request.allowPendingRemoteAnimationRegistryLookup;
@@ -435,6 +428,77 @@
             originatingPendingIntent = request.originatingPendingIntent;
             allowBackgroundActivityStart = request.allowBackgroundActivityStart;
         }
+
+        /**
+         * Resolve activity from the given intent for this launch.
+         */
+        void resolveActivity(ActivityStackSupervisor supervisor) {
+            if (realCallingPid == Request.DEFAULT_REAL_CALLING_PID) {
+                realCallingPid = Binder.getCallingPid();
+            }
+            if (realCallingUid == Request.DEFAULT_REAL_CALLING_UID) {
+                realCallingUid = Binder.getCallingUid();
+            }
+
+            if (callingUid >= 0) {
+                callingPid = -1;
+            } else if (caller == null) {
+                callingPid = realCallingPid;
+                callingUid = realCallingUid;
+            } else {
+                callingPid = callingUid = -1;
+            }
+
+            // Save a copy in case ephemeral needs it
+            ephemeralIntent = new Intent(intent);
+            // Don't modify the client's object!
+            intent = new Intent(intent);
+            if (intent.getComponent() != null
+                    && !(Intent.ACTION_VIEW.equals(intent.getAction()) && intent.getData() == null)
+                    && !Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE.equals(intent.getAction())
+                    && !Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE.equals(intent.getAction())
+                    && supervisor.mService.getPackageManagerInternalLocked()
+                            .isInstantAppInstallerComponent(intent.getComponent())) {
+                // Intercept intents targeted directly to the ephemeral installer the ephemeral
+                // installer should never be started with a raw Intent; instead adjust the intent
+                // so it looks like a "normal" instant app launch.
+                intent.setComponent(null /* component */);
+            }
+
+            resolveInfo = supervisor.resolveIntent(intent, resolvedType, userId,
+                    0 /* matchFlags */,
+                    computeResolveFilterUid(callingUid, realCallingUid, filterCallingUid));
+            if (resolveInfo == null) {
+                final UserInfo userInfo = supervisor.getUserInfo(userId);
+                if (userInfo != null && userInfo.isManagedProfile()) {
+                    // Special case for managed profiles, if attempting to launch non-cryto aware
+                    // app in a locked managed profile from an unlocked parent allow it to resolve
+                    // as user will be sent via confirm credentials to unlock the profile.
+                    final UserManager userManager = UserManager.get(supervisor.mService.mContext);
+                    boolean profileLockedAndParentUnlockingOrUnlocked = false;
+                    final long token = Binder.clearCallingIdentity();
+                    try {
+                        final UserInfo parent = userManager.getProfileParent(userId);
+                        profileLockedAndParentUnlockingOrUnlocked = (parent != null)
+                                && userManager.isUserUnlockingOrUnlocked(parent.id)
+                                && !userManager.isUserUnlockingOrUnlocked(userId);
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                    if (profileLockedAndParentUnlockingOrUnlocked) {
+                        resolveInfo = supervisor.resolveIntent(intent, resolvedType, userId,
+                                PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                                computeResolveFilterUid(callingUid, realCallingUid,
+                                        filterCallingUid));
+                    }
+                }
+            }
+
+            // Collect information about the target of the Intent.
+            activityInfo = supervisor.resolveActivity(intent, resolveInfo, startFlags,
+                    profilerInfo);
+        }
     }
 
     ActivityStarter(ActivityStartController controller, ActivityTaskManagerService service,
@@ -494,46 +558,95 @@
         mRequest.set(starter.mRequest);
     }
 
-    ActivityRecord getStartActivity() {
-        return mStartActivity;
-    }
-
     boolean relatedToPackage(String packageName) {
-        return (mLastStartActivityRecord[0] != null
-                && packageName.equals(mLastStartActivityRecord[0].packageName))
+        return (mLastStartActivityRecord != null
+                && packageName.equals(mLastStartActivityRecord.packageName))
                 || (mStartActivity != null && packageName.equals(mStartActivity.packageName));
     }
 
     /**
-     * Starts an activity based on the request parameters provided earlier.
+     * Starts an activity based on the provided {@link ActivityRecord} and environment parameters.
+     * Note that this method is called internally as well as part of {@link #executeRequest}.
+     */
+    void startResolvedActivity(final ActivityRecord r, ActivityRecord sourceRecord,
+            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
+        try {
+            mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(r.intent);
+            mLastStartReason = "startResolvedActivity";
+            mLastStartActivityTimeMs = System.currentTimeMillis();
+            mLastStartActivityRecord = r;
+            mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
+                    voiceInteractor, startFlags, doResume, options, inTask,
+                    false /* restrictedBgActivity */);
+            mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(mLastStartActivityResult,
+                    mLastStartActivityRecord);
+        } finally {
+            onExecutionComplete();
+        }
+    }
+
+    /**
+     * Resolve necessary information according the request parameters provided earlier, and execute
+     * the request which begin the journey of starting an activity.
      * @return The starter result.
      */
     int execute() {
         try {
-            // TODO(b/64750076): Look into passing request directly to these methods to allow
-            // for transactional diffs and preprocessing.
-            if (mRequest.mayWait) {
-                return startActivityMayWait(mRequest.caller, mRequest.callingUid,
-                        mRequest.callingPackage, mRequest.realCallingPid, mRequest.realCallingUid,
-                        mRequest.intent, mRequest.resolvedType,
-                        mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
-                        mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
-                        mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
-                        mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
-                        mRequest.inTask, mRequest.reason,
-                        mRequest.allowPendingRemoteAnimationRegistryLookup,
-                        mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart);
-            } else {
-                return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,
-                        mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,
-                        mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
-                        mRequest.resultWho, mRequest.requestCode, mRequest.callingPid,
-                        mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid,
-                        mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions,
-                        mRequest.ignoreTargetSecurity, mRequest.componentSpecified,
-                        mRequest.outActivity, mRequest.inTask, mRequest.reason,
-                        mRequest.allowPendingRemoteAnimationRegistryLookup,
-                        mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart);
+            // Refuse possible leaked file descriptors
+            if (mRequest.intent != null && mRequest.intent.hasFileDescriptors()) {
+                throw new IllegalArgumentException("File descriptors passed in Intent");
+            }
+
+            mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(mRequest.intent);
+
+            if (mRequest.activityInfo == null) {
+                mRequest.resolveActivity(mSupervisor);
+            }
+
+            int res;
+            synchronized (mService.mGlobalLock) {
+                final ActivityStack stack = mRootActivityContainer.getTopDisplayFocusedStack();
+                stack.mConfigWillChange = mRequest.globalConfig != null
+                        && mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0;
+                if (DEBUG_CONFIGURATION) {
+                    Slog.v(TAG_CONFIGURATION, "Starting activity when config will change = "
+                            + stack.mConfigWillChange);
+                }
+
+                final long origId = Binder.clearCallingIdentity();
+
+                res = resolveToHeavyWeightSwitcherIfNeeded();
+                if (res != START_SUCCESS) {
+                    return res;
+                }
+                res = executeRequest(mRequest);
+
+                Binder.restoreCallingIdentity(origId);
+
+                if (stack.mConfigWillChange) {
+                    // If the caller also wants to switch to a new configuration, do so now.
+                    // This allows a clean switch, as we are waiting for the current activity
+                    // to pause (so we will not destroy it), and have not yet started the
+                    // next activity.
+                    mService.mAmInternal.enforceCallingPermission(
+                            android.Manifest.permission.CHANGE_CONFIGURATION,
+                            "updateConfiguration()");
+                    stack.mConfigWillChange = false;
+                    if (DEBUG_CONFIGURATION) {
+                        Slog.v(TAG_CONFIGURATION,
+                                "Updating to new configuration after starting activity.");
+                    }
+                    mService.updateConfigurationLocked(mRequest.globalConfig, null, false);
+                }
+
+                // Notify ActivityMetricsLogger that the activity has launched.
+                // ActivityMetricsLogger will then wait for the windows to be drawn and populate
+                // WaitResult.
+                mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res,
+                        mLastStartActivityRecord);
+                return getExternalResult(mRequest.waitResult == null ? res
+                        : waitForResult(res, mLastStartActivityRecord));
             }
         } finally {
             onExecutionComplete();
@@ -541,89 +654,165 @@
     }
 
     /**
-     * Starts an activity based on the provided {@link ActivityRecord} and environment parameters.
-     * Note that this method is called internally as well as part of {@link #startActivity}.
-     *
-     * @return The start result.
+     * Updates the request to heavy-weight switch if this is a heavy-weight process while there
+     * already have another, different heavy-weight process running.
      */
-    int startResolvedActivity(final ActivityRecord r, ActivityRecord sourceRecord,
-            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
-            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
-        try {
-            mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(r.intent);
-            mLastStartReason = "startResolvedActivity";
-            mLastStartActivityTimeMs = System.currentTimeMillis();
-            mLastStartActivityRecord[0] = r;
-            mLastStartActivityResult = startActivity(r, sourceRecord, voiceSession, voiceInteractor,
-                    startFlags, doResume, options, inTask, mLastStartActivityRecord,
-                    false /* restrictedBgActivity */);
-            mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(mLastStartActivityResult,
-                    mLastStartActivityRecord[0]);
-            return mLastStartActivityResult;
-        } finally {
-            onExecutionComplete();
-        }
-    }
-
-    private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
-            String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
-            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
-            IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
-            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
-            SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
-            ActivityRecord[] outActivity, TaskRecord inTask, String reason,
-            boolean allowPendingRemoteAnimationRegistryLookup,
-            PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
-
-        if (TextUtils.isEmpty(reason)) {
-            throw new IllegalArgumentException("Need to specify a reason.");
-        }
-        mLastStartReason = reason;
-        mLastStartActivityTimeMs = System.currentTimeMillis();
-        mLastStartActivityRecord[0] = null;
-
-        mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
-                aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
-                callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
-                options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
-                inTask, allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent,
-                allowBackgroundActivityStart);
-
-        if (outActivity != null) {
-            // mLastStartActivityRecord[0] is set in the call to startActivity above.
-            outActivity[0] = mLastStartActivityRecord[0];
+    private int resolveToHeavyWeightSwitcherIfNeeded() {
+        if (mRequest.activityInfo == null || !mService.mHasHeavyWeightFeature
+                || (mRequest.activityInfo.applicationInfo.privateFlags
+                        & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) == 0) {
+            return START_SUCCESS;
         }
 
-        return getExternalResult(mLastStartActivityResult);
-    }
+        if (!mRequest.activityInfo.processName.equals(
+                mRequest.activityInfo.applicationInfo.packageName)) {
+            return START_SUCCESS;
+        }
 
-    static int getExternalResult(int result) {
-        // Aborted results are treated as successes externally, but we must track them internally.
-        return result != START_ABORTED ? result : START_SUCCESS;
+        final WindowProcessController heavy = mService.mHeavyWeightProcess;
+        if (heavy == null || (heavy.mInfo.uid == mRequest.activityInfo.applicationInfo.uid
+                && heavy.mName.equals(mRequest.activityInfo.processName))) {
+            return START_SUCCESS;
+        }
+
+        int appCallingUid = mRequest.callingUid;
+        if (mRequest.caller != null) {
+            WindowProcessController callerApp = mService.getProcessController(mRequest.caller);
+            if (callerApp != null) {
+                appCallingUid = callerApp.mInfo.uid;
+            } else {
+                Slog.w(TAG, "Unable to find app for caller " + mRequest.caller + " (pid="
+                        + mRequest.callingPid + ") when starting: " + mRequest.intent.toString());
+                SafeActivityOptions.abort(mRequest.activityOptions);
+                return ActivityManager.START_PERMISSION_DENIED;
+            }
+        }
+
+        final IIntentSender target = mService.getIntentSenderLocked(
+                ActivityManager.INTENT_SENDER_ACTIVITY, "android" /* packageName */, appCallingUid,
+                mRequest.userId, null /* token */, null /* resultWho*/, 0 /* requestCode*/,
+                new Intent[] { mRequest.intent }, new String[] { mRequest.resolvedType },
+                PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT,
+                null /* bOptions */);
+
+        final Intent newIntent = new Intent();
+        if (mRequest.requestCode >= 0) {
+            // Caller is requesting a result.
+            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
+        }
+        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT, new IntentSender(target));
+        heavy.updateIntentForHeavyWeightActivity(newIntent);
+        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
+                mRequest.activityInfo.packageName);
+        newIntent.setFlags(mRequest.intent.getFlags());
+        newIntent.setClassName("android" /* packageName */,
+                HeavyWeightSwitcherActivity.class.getName());
+        mRequest.intent = newIntent;
+        mRequest.resolvedType = null;
+        mRequest.caller = null;
+        mRequest.callingUid = Binder.getCallingUid();
+        mRequest.callingPid = Binder.getCallingPid();
+        mRequest.componentSpecified = true;
+        mRequest.resolveInfo = mSupervisor.resolveIntent(mRequest.intent, null /* resolvedType */,
+                mRequest.userId, 0 /* matchFlags */,
+                computeResolveFilterUid(mRequest.callingUid, mRequest.realCallingUid,
+                        mRequest.filterCallingUid));
+        mRequest.activityInfo =
+                mRequest.resolveInfo != null ? mRequest.resolveInfo.activityInfo : null;
+        if (mRequest.activityInfo != null) {
+            mRequest.activityInfo = mService.mAmInternal.getActivityInfoForUser(
+                    mRequest.activityInfo, mRequest.userId);
+        }
+
+        return START_SUCCESS;
     }
 
     /**
-     * Called when execution is complete. Sets state indicating completion and proceeds with
-     * recycling if appropriate.
+     * Wait for activity launch completes.
      */
-    private void onExecutionComplete() {
-        mController.onExecutionComplete(this);
+    private int waitForResult(int res, ActivityRecord r) {
+        mRequest.waitResult.result = res;
+        switch(res) {
+            case START_SUCCESS: {
+                mSupervisor.mWaitingActivityLaunched.add(mRequest.waitResult);
+                do {
+                    try {
+                        mService.mGlobalLock.wait();
+                    } catch (InterruptedException e) {
+                    }
+                } while (mRequest.waitResult.result != START_TASK_TO_FRONT
+                        && !mRequest.waitResult.timeout && mRequest.waitResult.who == null);
+                if (mRequest.waitResult.result == START_TASK_TO_FRONT) {
+                    res = START_TASK_TO_FRONT;
+                }
+                break;
+            }
+            case START_DELIVERED_TO_TOP: {
+                mRequest.waitResult.timeout = false;
+                mRequest.waitResult.who = r.mActivityComponent;
+                mRequest.waitResult.totalTime = 0;
+                break;
+            }
+            case START_TASK_TO_FRONT: {
+                mRequest.waitResult.launchState =
+                        r.attachedToProcess() ? LAUNCH_STATE_HOT : LAUNCH_STATE_COLD;
+                // ActivityRecord may represent a different activity, but it should not be
+                // in the resumed state.
+                if (r.nowVisible && r.isState(RESUMED)) {
+                    mRequest.waitResult.timeout = false;
+                    mRequest.waitResult.who = r.mActivityComponent;
+                    mRequest.waitResult.totalTime = 0;
+                } else {
+                    mSupervisor.waitActivityVisible(r.mActivityComponent, mRequest.waitResult);
+                    // Note: the timeout variable is not currently not ever set.
+                    do {
+                        try {
+                            mService.mGlobalLock.wait();
+                        } catch (InterruptedException e) {
+                        }
+                    } while (!mRequest.waitResult.timeout && mRequest.waitResult.who == null);
+                }
+                break;
+            }
+        }
+        return res;
     }
 
-    private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
-            String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
-            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
-            IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
-            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
-            SafeActivityOptions options,
-            boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
-            TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup,
-            PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
-        mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent);
+    /**
+     * Executing activity start request and starts the journey of starting an activity. Here
+     * begins with performing several preliminary checks. The normally activity launch flow will
+     * go through {@link #startActivityUnchecked} to {@link #startActivityInner}.
+     */
+    private int executeRequest(Request request) {
+        if (TextUtils.isEmpty(request.reason)) {
+            throw new IllegalArgumentException("Need to specify a reason.");
+        }
+        mLastStartReason = request.reason;
+        mLastStartActivityTimeMs = System.currentTimeMillis();
+        mLastStartActivityRecord = null;
+
+        final IApplicationThread caller = request.caller;
+        Intent intent = request.intent;
+        String resolvedType = request.resolvedType;
+        ActivityInfo aInfo = request.activityInfo;
+        ResolveInfo rInfo = request.resolveInfo;
+        final IVoiceInteractionSession voiceSession = request.voiceSession;
+        final IBinder resultTo = request.resultTo;
+        String resultWho = request.resultWho;
+        int requestCode = request.requestCode;
+        int callingPid = request.callingPid;
+        int callingUid = request.callingUid;
+        String callingPackage = request.callingPackage;
+        final int realCallingPid = request.realCallingPid;
+        final int realCallingUid = request.realCallingUid;
+        final int startFlags = request.startFlags;
+        final SafeActivityOptions options = request.activityOptions;
+        TaskRecord inTask = request.inTask;
+
         int err = ActivityManager.START_SUCCESS;
         // Pull the optional Ephemeral Installer-only bundle out of the options early.
-        final Bundle verificationBundle
-                = options != null ? options.popAppVerificationBundle() : null;
+        final Bundle verificationBundle =
+                options != null ? options.popAppVerificationBundle() : null;
 
         WindowProcessController callerApp = null;
         if (caller != null) {
@@ -632,16 +821,14 @@
                 callingPid = callerApp.getPid();
                 callingUid = callerApp.mInfo.uid;
             } else {
-                Slog.w(TAG, "Unable to find app for caller " + caller
-                        + " (pid=" + callingPid + ") when starting: "
-                        + intent.toString());
+                Slog.w(TAG, "Unable to find app for caller " + caller + " (pid=" + callingPid
+                        + ") when starting: " + intent.toString());
                 err = ActivityManager.START_PERMISSION_DENIED;
             }
         }
 
         final int userId = aInfo != null && aInfo.applicationInfo != null
                 ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
-
         if (err == ActivityManager.START_SUCCESS) {
             Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
                     + "} from uid " + callingUid);
@@ -651,8 +838,9 @@
         ActivityRecord resultRecord = null;
         if (resultTo != null) {
             sourceRecord = mRootActivityContainer.isInAnyStack(resultTo);
-            if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
-                    "Will send result to " + resultTo + " " + sourceRecord);
+            if (DEBUG_RESULTS) {
+                Slog.v(TAG_RESULTS, "Will send result to " + resultTo + " " + sourceRecord);
+            }
             if (sourceRecord != null) {
                 if (requestCode >= 0 && !sourceRecord.finishing) {
                     resultRecord = sourceRecord;
@@ -661,10 +849,9 @@
         }
 
         final int launchFlags = intent.getFlags();
-
         if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
-            // Transfer the result target from the source activity to the new
-            // one being started, including any failures.
+            // Transfer the result target from the source activity to the new one being started,
+            // including any failures.
             if (requestCode >= 0) {
                 SafeActivityOptions.abort(options);
                 return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
@@ -680,16 +867,16 @@
                 resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
             }
             if (sourceRecord.launchedFromUid == callingUid) {
-                // The new activity is being launched from the same uid as the previous
-                // activity in the flow, and asking to forward its result back to the
-                // previous.  In this case the activity is serving as a trampoline between
-                // the two, so we also want to update its launchedFromPackage to be the
-                // same as the previous activity.  Note that this is safe, since we know
-                // these two packages come from the same uid; the caller could just as
-                // well have supplied that same package name itself.  This specifially
-                // deals with the case of an intent picker/chooser being launched in the app
-                // flow to redirect to an activity picked by the user, where we want the final
-                // activity to consider it to have been launched by the previous app activity.
+                // The new activity is being launched from the same uid as the previous activity
+                // in the flow, and asking to forward its result back to the previous.  In this
+                // case the activity is serving as a trampoline between the two, so we also want
+                // to update its launchedFromPackage to be the same as the previous activity.
+                // Note that this is safe, since we know these two packages come from the same
+                // uid; the caller could just as well have supplied that same package name itself
+                // . This specifially deals with the case of an intent picker/chooser being
+                // launched in the app flow to redirect to an activity picked by the user, where
+                // we want the final activity to consider it to have been launched by the
+                // previous app activity.
                 callingPackage = sourceRecord.launchedFromPackage;
             }
         }
@@ -708,19 +895,18 @@
 
         if (err == ActivityManager.START_SUCCESS && sourceRecord != null
                 && sourceRecord.getTaskRecord().voiceSession != null) {
-            // If this activity is being launched as part of a voice session, we need
-            // to ensure that it is safe to do so.  If the upcoming activity will also
-            // be part of the voice session, we can only launch it if it has explicitly
-            // said it supports the VOICE category, or it is a part of the calling app.
+            // If this activity is being launched as part of a voice session, we need to ensure
+            // that it is safe to do so.  If the upcoming activity will also be part of the voice
+            // session, we can only launch it if it has explicitly said it supports the VOICE
+            // category, or it is a part of the calling app.
             if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0
                     && sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
                 try {
                     intent.addCategory(Intent.CATEGORY_VOICE);
                     if (!mService.getPackageManager().activitySupportsIntent(
                             intent.getComponent(), intent, resolvedType)) {
-                        Slog.w(TAG,
-                                "Activity being started in current voice task does not support voice: "
-                                        + intent);
+                        Slog.w(TAG, "Activity being started in current voice task does not support "
+                                + "voice: " + intent);
                         err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
                     }
                 } catch (RemoteException e) {
@@ -737,8 +923,7 @@
                 if (!mService.getPackageManager().activitySupportsIntent(intent.getComponent(),
                         intent, resolvedType)) {
                     Slog.w(TAG,
-                            "Activity being started in new voice task does not support: "
-                                    + intent);
+                            "Activity being started in new voice task does not support: " + intent);
                     err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
                 }
             } catch (RemoteException e) {
@@ -760,7 +945,7 @@
         }
 
         boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
-                requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity,
+                requestCode, callingPid, callingUid, callingPackage, request.ignoreTargetSecurity,
                 inTask != null, callerApp, resultRecord, resultStack);
         abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
                 callingPid, resolvedType, aInfo.applicationInfo);
@@ -774,7 +959,8 @@
                         "shouldAbortBackgroundActivityStart");
                 restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid,
                         callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,
-                        originatingPendingIntent, allowBackgroundActivityStart, intent);
+                        request.originatingPendingIntent, request.allowBackgroundActivityStart,
+                        intent);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
             }
@@ -783,15 +969,15 @@
         // Merge the two options bundles, while realCallerOptions takes precedence.
         ActivityOptions checkedOptions = options != null
                 ? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;
-        if (allowPendingRemoteAnimationRegistryLookup) {
+        if (request.allowPendingRemoteAnimationRegistryLookup) {
             checkedOptions = mService.getActivityStartController()
                     .getPendingRemoteAnimationRegistry()
                     .overrideOptionsIfNeeded(callingPackage, checkedOptions);
         }
         if (mService.mController != null) {
             try {
-                // The Intent we give to the watcher has the extra data
-                // stripped off, since it can contain private information.
+                // The Intent we give to the watcher has the extra data stripped off, since it
+                // can contain private information.
                 Intent watchIntent = intent.cloneFilter();
                 abort |= !mService.mController.activityStarting(watchIntent,
                         aInfo.applicationInfo.packageName);
@@ -820,8 +1006,8 @@
                 resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED,
                         null /* data */);
             }
-            // We pretend to the caller that it was really started, but
-            // they will just get a cancel result.
+            // We pretend to the caller that it was really started, but they will just get a
+            // cancel result.
             ActivityOptions.abort(checkedOptions);
             return START_ABORTED;
         }
@@ -832,7 +1018,7 @@
         if (aInfo != null) {
             if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
                     aInfo.packageName, userId)) {
-                IIntentSender target = mService.getIntentSenderLocked(
+                final IIntentSender target = mService.getIntentSenderLocked(
                         ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
                         callingUid, userId, null, null, 0, new Intent[]{intent},
                         new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT
@@ -870,7 +1056,7 @@
 
                 rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, 0,
                         computeResolveFilterUid(
-                                callingUid, realCallingUid, mRequest.filterCallingUid));
+                                callingUid, realCallingUid, request.filterCallingUid));
                 aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
                         null /*profilerInfo*/);
 
@@ -889,7 +1075,7 @@
         // starts either the intent we resolved here [on install error] or the ephemeral
         // app [on install success].
         if (rInfo != null && rInfo.auxiliaryInfo != null) {
-            intent = createLaunchIntent(rInfo.auxiliaryInfo, ephemeralIntent,
+            intent = createLaunchIntent(rInfo.auxiliaryInfo, request.ephemeralIntent,
                     callingPackage, verificationBundle, resolvedType, userId);
             resolvedType = null;
             callingUid = realCallingUid;
@@ -898,13 +1084,11 @@
             aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
         }
 
-        ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
+        final ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
                 callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
-                resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
-                mSupervisor, checkedOptions, sourceRecord);
-        if (outActivity != null) {
-            outActivity[0] = r;
-        }
+                resultRecord, resultWho, requestCode, request.componentSpecified,
+                voiceSession != null, mSupervisor, checkedOptions, sourceRecord);
+        mLastStartActivityRecord = r;
 
         if (r.appTimeTracker == null && sourceRecord != null) {
             // If the caller didn't specify an explicit time tracker, we want to continue
@@ -932,10 +1116,52 @@
         mService.onStartActivitySetDidAppSwitch();
         mController.doPendingActivityLaunches(false);
 
-        final int res = startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
-                true /* doResume */, checkedOptions, inTask, outActivity, restrictedBgActivity);
-        mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outActivity[0]);
-        return res;
+        mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
+                request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,
+                restrictedBgActivity);
+
+        if (request.outActivity != null) {
+            request.outActivity[0] = mLastStartActivityRecord;
+        }
+
+        return getExternalResult(mLastStartActivityResult);
+    }
+
+    /**
+     * Return true if background activity is really aborted.
+     *
+     * TODO(b/131748165): Refactor the logic so we don't need to call this method everywhere.
+     */
+    private boolean handleBackgroundActivityAbort(ActivityRecord r) {
+        // TODO(b/131747138): Remove toast and refactor related code in R release.
+        final boolean abort = !mService.isBackgroundActivityStartsEnabled();
+        if (!abort) {
+            return false;
+        }
+        final ActivityRecord resultRecord = r.resultTo;
+        final String resultWho = r.resultWho;
+        int requestCode = r.requestCode;
+        if (resultRecord != null) {
+            resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED,
+                    null /* data */);
+        }
+        // We pretend to the caller that it was really started to make it backward compatible, but
+        // they will just get a cancel result.
+        ActivityOptions.abort(r.pendingOptions);
+        return true;
+    }
+
+    static int getExternalResult(int result) {
+        // Aborted results are treated as successes externally, but we must track them internally.
+        return result != START_ABORTED ? result : START_SUCCESS;
+    }
+
+    /**
+     * Called when execution is complete. Sets state indicating completion and proceeds with
+     * recycling if appropriate.
+     */
+    private void onExecutionComplete() {
+        mController.onExecutionComplete(this);
     }
 
     boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
@@ -1110,8 +1336,8 @@
         // We're waiting for an activity launch to finish, but that activity simply
         // brought another activity to front. We must also handle the case where the task is already
         // in the front as a result of the trampoline activity being in the same task (it will be
-        // considered focused as the trampoline will be finished). Let startActivityMayWait() know
-        // about this, so it waits for the new activity to become visible instead.
+        // considered focused as the trampoline will be finished). Let them know about this, so
+        // it waits for the new activity to become visible instead, {@link #waitResultIfNeeded}.
         mSupervisor.reportWaitingActivityLaunchedIfNeeded(r, result);
 
         if (startedActivityStack == null) {
@@ -1141,241 +1367,6 @@
         }
     }
 
-    private int startActivityMayWait(IApplicationThread caller, int callingUid,
-            String callingPackage, int requestRealCallingPid, int requestRealCallingUid,
-            Intent intent, String resolvedType, IVoiceInteractionSession voiceSession,
-            IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode,
-            int startFlags, ProfilerInfo profilerInfo, WaitResult outResult,
-            Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity,
-            int userId, TaskRecord inTask, String reason,
-            boolean allowPendingRemoteAnimationRegistryLookup,
-            PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
-        // Refuse possible leaked file descriptors
-        if (intent != null && intent.hasFileDescriptors()) {
-            throw new IllegalArgumentException("File descriptors passed in Intent");
-        }
-        mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent);
-        boolean componentSpecified = intent.getComponent() != null;
-
-        final int realCallingPid = requestRealCallingPid != Request.DEFAULT_REAL_CALLING_PID
-                ? requestRealCallingPid
-                : Binder.getCallingPid();
-        final int realCallingUid = requestRealCallingUid != Request.DEFAULT_REAL_CALLING_UID
-                ? requestRealCallingUid
-                : Binder.getCallingUid();
-
-        int callingPid;
-        if (callingUid >= 0) {
-            callingPid = -1;
-        } else if (caller == null) {
-            callingPid = realCallingPid;
-            callingUid = realCallingUid;
-        } else {
-            callingPid = callingUid = -1;
-        }
-
-        // Save a copy in case ephemeral needs it
-        final Intent ephemeralIntent = new Intent(intent);
-        // Don't modify the client's object!
-        intent = new Intent(intent);
-        if (componentSpecified
-                && !(Intent.ACTION_VIEW.equals(intent.getAction()) && intent.getData() == null)
-                && !Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE.equals(intent.getAction())
-                && !Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE.equals(intent.getAction())
-                && mService.getPackageManagerInternalLocked()
-                        .isInstantAppInstallerComponent(intent.getComponent())) {
-            // intercept intents targeted directly to the ephemeral installer the
-            // ephemeral installer should never be started with a raw Intent; instead
-            // adjust the intent so it looks like a "normal" instant app launch
-            intent.setComponent(null /*component*/);
-            componentSpecified = false;
-        }
-
-        ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
-                0 /* matchFlags */,
-                        computeResolveFilterUid(
-                                callingUid, realCallingUid, mRequest.filterCallingUid));
-        if (rInfo == null) {
-            UserInfo userInfo = mSupervisor.getUserInfo(userId);
-            if (userInfo != null && userInfo.isManagedProfile()) {
-                // Special case for managed profiles, if attempting to launch non-cryto aware
-                // app in a locked managed profile from an unlocked parent allow it to resolve
-                // as user will be sent via confirm credentials to unlock the profile.
-                UserManager userManager = UserManager.get(mService.mContext);
-                boolean profileLockedAndParentUnlockingOrUnlocked = false;
-                long token = Binder.clearCallingIdentity();
-                try {
-                    UserInfo parent = userManager.getProfileParent(userId);
-                    profileLockedAndParentUnlockingOrUnlocked = (parent != null)
-                            && userManager.isUserUnlockingOrUnlocked(parent.id)
-                            && !userManager.isUserUnlockingOrUnlocked(userId);
-                } finally {
-                    Binder.restoreCallingIdentity(token);
-                }
-                if (profileLockedAndParentUnlockingOrUnlocked) {
-                    rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
-                            PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
-                            computeResolveFilterUid(
-                                    callingUid, realCallingUid, mRequest.filterCallingUid));
-                }
-            }
-        }
-        // Collect information about the target of the Intent.
-        ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
-
-        synchronized (mService.mGlobalLock) {
-            final ActivityStack stack = mRootActivityContainer.getTopDisplayFocusedStack();
-            stack.mConfigWillChange = globalConfig != null
-                    && mService.getGlobalConfiguration().diff(globalConfig) != 0;
-            if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                    "Starting activity when config will change = " + stack.mConfigWillChange);
-
-            final long origId = Binder.clearCallingIdentity();
-
-            if (aInfo != null &&
-                    (aInfo.applicationInfo.privateFlags
-                            & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0 &&
-                    mService.mHasHeavyWeightFeature) {
-                // This may be a heavy-weight process!  Check to see if we already
-                // have another, different heavy-weight process running.
-                if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
-                    final WindowProcessController heavy = mService.mHeavyWeightProcess;
-                    if (heavy != null && (heavy.mInfo.uid != aInfo.applicationInfo.uid
-                            || !heavy.mName.equals(aInfo.processName))) {
-                        int appCallingUid = callingUid;
-                        if (caller != null) {
-                            WindowProcessController callerApp =
-                                    mService.getProcessController(caller);
-                            if (callerApp != null) {
-                                appCallingUid = callerApp.mInfo.uid;
-                            } else {
-                                Slog.w(TAG, "Unable to find app for caller " + caller
-                                        + " (pid=" + callingPid + ") when starting: "
-                                        + intent.toString());
-                                SafeActivityOptions.abort(options);
-                                return ActivityManager.START_PERMISSION_DENIED;
-                            }
-                        }
-
-                        IIntentSender target = mService.getIntentSenderLocked(
-                                ActivityManager.INTENT_SENDER_ACTIVITY, "android",
-                                appCallingUid, userId, null, null, 0, new Intent[] { intent },
-                                new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT
-                                        | PendingIntent.FLAG_ONE_SHOT, null);
-
-                        Intent newIntent = new Intent();
-                        if (requestCode >= 0) {
-                            // Caller is requesting a result.
-                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
-                        }
-                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
-                                new IntentSender(target));
-                        heavy.updateIntentForHeavyWeightActivity(newIntent);
-                        newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
-                                aInfo.packageName);
-                        newIntent.setFlags(intent.getFlags());
-                        newIntent.setClassName("android",
-                                HeavyWeightSwitcherActivity.class.getName());
-                        intent = newIntent;
-                        resolvedType = null;
-                        caller = null;
-                        callingUid = Binder.getCallingUid();
-                        callingPid = Binder.getCallingPid();
-                        componentSpecified = true;
-                        rInfo = mSupervisor.resolveIntent(intent, null /*resolvedType*/, userId,
-                                0 /* matchFlags */, computeResolveFilterUid(
-                                        callingUid, realCallingUid, mRequest.filterCallingUid));
-                        aInfo = rInfo != null ? rInfo.activityInfo : null;
-                        if (aInfo != null) {
-                            aInfo = mService.mAmInternal.getActivityInfoForUser(aInfo, userId);
-                        }
-                    }
-                }
-            }
-
-            final ActivityRecord[] outRecord = new ActivityRecord[1];
-            int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo,
-                    voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid,
-                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options,
-                    ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason,
-                    allowPendingRemoteAnimationRegistryLookup, originatingPendingIntent,
-                    allowBackgroundActivityStart);
-
-            Binder.restoreCallingIdentity(origId);
-
-            if (stack.mConfigWillChange) {
-                // If the caller also wants to switch to a new configuration,
-                // do so now.  This allows a clean switch, as we are waiting
-                // for the current activity to pause (so we will not destroy
-                // it), and have not yet started the next activity.
-                mService.mAmInternal.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
-                        "updateConfiguration()");
-                stack.mConfigWillChange = false;
-                if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
-                        "Updating to new configuration after starting activity.");
-                mService.updateConfigurationLocked(globalConfig, null, false);
-            }
-
-            // Notify ActivityMetricsLogger that the activity has launched. ActivityMetricsLogger
-            // will then wait for the windows to be drawn and populate WaitResult.
-            mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outRecord[0]);
-            if (outResult != null) {
-                outResult.result = res;
-
-                final ActivityRecord r = outRecord[0];
-
-                switch(res) {
-                    case START_SUCCESS: {
-                        mSupervisor.mWaitingActivityLaunched.add(outResult);
-                        do {
-                            try {
-                                mService.mGlobalLock.wait();
-                            } catch (InterruptedException e) {
-                            }
-                        } while (outResult.result != START_TASK_TO_FRONT
-                                && !outResult.timeout && outResult.who == null);
-                        if (outResult.result == START_TASK_TO_FRONT) {
-                            res = START_TASK_TO_FRONT;
-                        }
-                        break;
-                    }
-                    case START_DELIVERED_TO_TOP: {
-                        outResult.timeout = false;
-                        outResult.who = r.mActivityComponent;
-                        outResult.totalTime = 0;
-                        break;
-                    }
-                    case START_TASK_TO_FRONT: {
-                        outResult.launchState =
-                                r.attachedToProcess() ? LAUNCH_STATE_HOT : LAUNCH_STATE_COLD;
-                        // ActivityRecord may represent a different activity, but it should not be
-                        // in the resumed state.
-                        if (r.nowVisible && r.isState(RESUMED)) {
-                            outResult.timeout = false;
-                            outResult.who = r.mActivityComponent;
-                            outResult.totalTime = 0;
-                        } else {
-                            final long startTimeMs = SystemClock.uptimeMillis();
-                            mSupervisor.waitActivityVisible(
-                                    r.mActivityComponent, outResult, startTimeMs);
-                            // Note: the timeout variable is not currently not ever set.
-                            do {
-                                try {
-                                    mService.mGlobalLock.wait();
-                                } catch (InterruptedException e) {
-                                }
-                            } while (!outResult.timeout && outResult.who == null);
-                        }
-                        break;
-                    }
-                }
-            }
-
-            return res;
-        }
-    }
-
     /**
      * Compute the logical UID based on which the package manager would filter
      * app components i.e. based on which the instant app policy would be applied
@@ -1393,17 +1384,22 @@
                 : (customCallingUid >= 0 ? customCallingUid : actualCallingUid);
     }
 
-    private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
+    /**
+     * Start an activity while most of preliminary checks has been done and caller has been
+     * confirmed that holds necessary permissions to do so.
+     * Here also ensures that the starting activity is removed if the start wasn't successful.
+     */
+    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
                 IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                 int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
-                ActivityRecord[] outActivity, boolean restrictedBgActivity) {
+                boolean restrictedBgActivity) {
         int result = START_CANCELED;
         final ActivityStack startedActivityStack;
         try {
             mService.deferWindowLayout();
             Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
             result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
-                    startFlags, doResume, options, inTask, outActivity, restrictedBgActivity);
+                    startFlags, doResume, options, inTask, restrictedBgActivity);
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
             startedActivityStack = handleStartResult(r, result);
@@ -1459,34 +1455,16 @@
     }
 
     /**
-     * Return true if background activity is really aborted.
+     * Start an activity and determine if the activity should be adding to the top of an existing
+     * task or delivered new intent to an existing activity. Also manipulating the activity task
+     * onto requested or valid stack/display.
      *
-     * TODO(b/131748165): Refactor the logic so we don't need to call this method everywhere.
+     * Note: This method should only be called from {@link #startActivityUnchecked}.
      */
-    private boolean handleBackgroundActivityAbort(ActivityRecord r) {
-        // TODO(b/131747138): Remove toast and refactor related code in R release.
-        final boolean abort = !mService.isBackgroundActivityStartsEnabled();
-        if (!abort) {
-            return false;
-        }
-        final ActivityRecord resultRecord = r.resultTo;
-        final String resultWho = r.resultWho;
-        int requestCode = r.requestCode;
-        if (resultRecord != null) {
-            resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED,
-                    null /* data */);
-        }
-        // We pretend to the caller that it was really started to make it backward compatible, but
-        // they will just get a cancel result.
-        ActivityOptions.abort(r.pendingOptions);
-        return true;
-    }
-
-    // Note: This method should only be called from {@link startActivity}.
     private int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
-            ActivityRecord[] outActivity, boolean restrictedBgActivity) {
+            boolean restrictedBgActivity) {
         setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
                 voiceInteractor, restrictedBgActivity);
 
@@ -1528,7 +1506,7 @@
         final ActivityRecord targetTaskTop = newTask ? null : targetTask.getTopActivity();
         if (targetTaskTop != null) {
             // Recycle the target task for this launch.
-            startResult = recycleTask(targetTask, targetTaskTop, reusedActivity, outActivity);
+            startResult = recycleTask(targetTask, targetTaskTop, reusedActivity);
             if (startResult != START_SUCCESS) {
                 return startResult;
             }
@@ -1690,7 +1668,7 @@
      * - Determine whether need to add a new activity on top or just brought the task to front.
      */
     private int recycleTask(TaskRecord targetTask, ActivityRecord targetTaskTop,
-            ActivityRecord reusedActivity, ActivityRecord[] outActivity) {
+            ActivityRecord reusedActivity) {
         // True if we are clearing top and resetting of a standard (default) launch mode
         // ({@code LAUNCH_MULTIPLE}) activity. The existing activity will be finished.
         final boolean clearTopAndResetStandardLaunchMode =
@@ -1729,13 +1707,11 @@
 
         setTargetStackIfNeeded(targetTaskTop);
 
-        final ActivityRecord outResult =
-                outActivity != null && outActivity.length > 0 ? outActivity[0] : null;
-
         // When there is a reused activity and the current result is a trampoline activity,
         // set the reused activity as the result.
-        if (outResult != null && (outResult.finishing || outResult.noDisplay)) {
-            outActivity[0] = targetTaskTop;
+        if (mLastStartActivityRecord != null
+                && (mLastStartActivityRecord.finishing || mLastStartActivityRecord.noDisplay)) {
+            mLastStartActivityRecord = targetTaskTop;
         }
 
         if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
@@ -1777,12 +1753,11 @@
         // We didn't do anything...  but it was needed (a.k.a., client don't use that intent!)
         // And for paranoia, make sure we have correctly resumed the top activity.
         resumeTargetStackIfNeeded();
-        if (outActivity != null && outActivity.length > 0) {
-            // The reusedActivity could be finishing, for example of starting an activity with
-            // FLAG_ACTIVITY_CLEAR_TOP flag. In that case, return the top running activity in the
-            // task instead.
-            outActivity[0] = targetTaskTop.finishing ? targetTask.getTopActivity() : targetTaskTop;
-        }
+        // The reusedActivity could be finishing, for example of starting an activity with
+        // FLAG_ACTIVITY_CLEAR_TOP flag. In that case, return the top running activity in the
+        // task instead.
+        mLastStartActivityRecord =
+                targetTaskTop.finishing ? targetTask.getTopActivity() : targetTaskTop;
         return mMovedToFront ? START_TASK_TO_FRONT : START_DELIVERED_TO_TOP;
     }
 
@@ -1864,9 +1839,8 @@
                     mLaunchFlags);
 
             // The above code can remove {@code reusedActivity} from the task, leading to the
-            // the {@code ActivityRecord} removing its reference to the {@code TaskRecord}. The
-            // task reference is needed in the call below to
-            // {@link setTargetStackAndMoveToFrontIfNeeded}.
+            // {@code ActivityRecord} removing its reference to the {@code TaskRecord}. The task
+            // reference is needed in the call below to {@link setTargetStackAndMoveToFrontIfNeeded}
             if (targetTaskTop.getTaskRecord() == null) {
                 targetTaskTop.setTask(targetTask);
             }
@@ -2377,7 +2351,7 @@
                     mMovedToFront = true;
                 }
 
-                if (launchStack.topTask() == null) {
+                if (launchStack != null && launchStack.topTask() == null) {
                     // The task does not need to be reparented to the launch stack. Remove the
                     // launch stack if there is no activity in it.
                     Slog.w(TAG, "Removing an empty stack: " + launchStack);
@@ -2450,7 +2424,7 @@
 
     private void addOrReparentStartingActivity(TaskRecord parent, String reason) {
         if (mStartActivity.getTaskRecord() == null || mStartActivity.getTaskRecord() == parent) {
-            parent.addActivityToTop(mStartActivity);
+            parent.addChild(mStartActivity);
         } else {
             mStartActivity.reparent(parent, parent.getChildCount() /* top */, reason);
         }
@@ -2652,12 +2626,6 @@
         return this;
     }
 
-    ActivityStarter setEphemeralIntent(Intent intent) {
-        mRequest.ephemeralIntent = intent;
-        return this;
-    }
-
-
     ActivityStarter setResolvedType(String type) {
         mRequest.resolvedType = type;
         return this;
@@ -2809,13 +2777,6 @@
         return this;
     }
 
-    ActivityStarter setMayWait(int userId) {
-        mRequest.mayWait = true;
-        mRequest.userId = userId;
-
-        return this;
-    }
-
     ActivityStarter setAllowPendingRemoteAnimationRegistryLookup(boolean allowLookup) {
         mRequest.allowPendingRemoteAnimationRegistryLookup = allowLookup;
         return this;
@@ -2845,11 +2806,10 @@
         pw.print(prefix);
         pw.print("mLastStartActivityResult=");
         pw.println(mLastStartActivityResult);
-        ActivityRecord r = mLastStartActivityRecord[0];
-        if (r != null) {
+        if (mLastStartActivityRecord != null) {
             pw.print(prefix);
             pw.println("mLastStartActivityRecord:");
-            r.dump(pw, prefix + "  ", true /* dumpAll */);
+            mLastStartActivityRecord.dump(pw, prefix + "  ", true /* dumpAll */);
         }
         if (mStartActivity != null) {
             pw.print(prefix);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 14df505..222f26e 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -54,6 +54,7 @@
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
+import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
 import static android.provider.Settings.Global.HIDE_ERROR_DIALOGS;
@@ -226,6 +227,7 @@
 import android.view.IRecentsAnimationRunner;
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationDefinition;
+import android.view.WindowContainerTransaction;
 import android.view.WindowManager;
 
 import com.android.internal.R;
@@ -288,6 +290,7 @@
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -569,6 +572,7 @@
     boolean mSupportsPictureInPicture;
     boolean mSupportsMultiDisplay;
     boolean mForceResizableActivities;
+    boolean mSizeCompatFreeform;
 
     final List<ActivityTaskManagerInternal.ScreenObserver> mScreenObservers = new ArrayList<>();
 
@@ -744,6 +748,8 @@
         final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
         final boolean forceResizable = Settings.Global.getInt(
                 resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
+        final boolean sizeCompatFreeform = Settings.Global.getInt(
+                resolver, DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM, 0) != 0;
 
         // Transfer any global setting for forcing RTL layout, into a System Property
         DisplayProperties.debug_force_rtl(forceRtl);
@@ -757,6 +763,7 @@
 
         synchronized (mGlobalLock) {
             mForceResizableActivities = forceResizable;
+            mSizeCompatFreeform = sizeCompatFreeform;
             final boolean multiWindowFormEnabled = freeformWindowManagement
                     || supportsSplitScreenMultiWindow
                     || supportsPictureInPicture
@@ -1056,7 +1063,7 @@
                 .setStartFlags(startFlags)
                 .setProfilerInfo(profilerInfo)
                 .setActivityOptions(bOptions)
-                .setMayWait(userId)
+                .setUserId(userId)
                 .execute();
 
     }
@@ -1227,7 +1234,7 @@
                     .setRequestCode(requestCode)
                     .setStartFlags(startFlags)
                     .setActivityOptions(bOptions)
-                    .setMayWait(userId)
+                    .setUserId(userId)
                     .setProfilerInfo(profilerInfo)
                     .setWaitResult(res)
                     .execute();
@@ -1254,7 +1261,7 @@
                     .setStartFlags(startFlags)
                     .setGlobalConfiguration(config)
                     .setActivityOptions(bOptions)
-                    .setMayWait(userId)
+                    .setUserId(userId)
                     .execute();
         }
     }
@@ -1384,7 +1391,7 @@
                     .setRequestCode(requestCode)
                     .setStartFlags(startFlags)
                     .setActivityOptions(bOptions)
-                    .setMayWait(userId)
+                    .setUserId(userId)
                     .setIgnoreTargetSecurity(ignoreTargetSecurity)
                     .setFilterCallingUid(isResolver ? 0 /* system */ : targetUid)
                     // The target may well be in the background, which would normally prevent it
@@ -1432,7 +1439,7 @@
                 .setStartFlags(startFlags)
                 .setProfilerInfo(profilerInfo)
                 .setActivityOptions(bOptions)
-                .setMayWait(userId)
+                .setUserId(userId)
                 .setAllowBackgroundActivityStart(true)
                 .execute();
     }
@@ -1448,7 +1455,7 @@
                 .setCallingPackage(callingPackage)
                 .setResolvedType(resolvedType)
                 .setActivityOptions(bOptions)
-                .setMayWait(userId)
+                .setUserId(userId)
                 .setAllowBackgroundActivityStart(true)
                 .execute();
     }
@@ -3244,6 +3251,47 @@
         }
     }
 
+    private void sanitizeAndApplyConfigChange(ConfigurationContainer container,
+            WindowContainerTransaction.Change change) {
+        if (!(container instanceof TaskRecord)) {
+            throw new RuntimeException("Invalid token in task transaction");
+        }
+        // The "client"-facing API should prevent bad changes; however, just in case, sanitize
+        // masks here.
+        int configMask = change.getConfigSetMask();
+        int windowMask = change.getWindowSetMask();
+        configMask &= ActivityInfo.CONFIG_WINDOW_CONFIGURATION
+                | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+        windowMask &= WindowConfiguration.WINDOW_CONFIG_BOUNDS;
+        Configuration c = new Configuration(container.getRequestedOverrideConfiguration());
+        c.setTo(change.getConfiguration(), configMask, windowMask);
+        container.onRequestedOverrideConfigurationChanged(c);
+    }
+
+    @Override
+    public void applyContainerTransaction(WindowContainerTransaction t) {
+        mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "applyContainerTransaction()");
+        long ident = Binder.clearCallingIdentity();
+        try {
+            if (t == null) {
+                return;
+            }
+            synchronized (mGlobalLock) {
+                Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =
+                        t.getChanges().entrySet().iterator();
+                while (entries.hasNext()) {
+                    final Map.Entry<IBinder, WindowContainerTransaction.Change> entry =
+                            entries.next();
+                    final ConfigurationContainer cc = ConfigurationContainer.RemoteToken.fromBinder(
+                            entry.getKey()).getContainer();
+                    sanitizeAndApplyConfigChange(cc, entry.getValue());
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
     @Override
     public boolean releaseActivityInstance(IBinder token) {
         synchronized (mGlobalLock) {
@@ -3393,6 +3441,9 @@
 
                 if (stack.inFreeformWindowingMode()) {
                     stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+                } else if (!mSizeCompatFreeform) {
+                    throw new IllegalStateException("Size-compat windows are currently not"
+                            + "freeform-enabled");
                 } else if (stack.getParent().inFreeformWindowingMode()) {
                     // If the window is on a freeform display, set it to undefined. It will be
                     // resolved to freeform and it can adjust windowing mode when the display mode
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 1eb7455..c5e190d 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -155,7 +155,7 @@
                 .setCallingPackage(callingPackage)
                 .setResolvedType(resolvedType)
                 .setActivityOptions(bOptions)
-                .setMayWait(callingUser)
+                .setUserId(callingUser)
                 .setInTask(tr)
                 .execute();
     }
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index c1143c8..cb9a200 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -219,7 +219,7 @@
     private int mNextAppTransitionExit;
     private int mNextAppTransitionInPlace;
 
-    // Keyed by task id.
+    // Keyed by WindowContainer hashCode.
     private final SparseArray<AppTransitionAnimationSpec> mNextAppTransitionAnimationsSpecs
             = new SparseArray<>();
     private IAppTransitionAnimationSpecsFuture mNextAppTransitionAnimationsSpecsFuture;
@@ -372,8 +372,9 @@
         setAppTransitionState(APP_STATE_TIMEOUT);
     }
 
-    GraphicBuffer getAppTransitionThumbnailHeader(int taskId) {
-        AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId);
+    GraphicBuffer getAppTransitionThumbnailHeader(WindowContainer container) {
+        AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(
+                container.hashCode());
         if (spec == null) {
             spec = mDefaultNextAppTransitionAnimationSpec;
         }
@@ -789,14 +790,15 @@
         }
     }
 
-    void getNextAppTransitionStartRect(int taskId, Rect rect) {
-        AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId);
+    void getNextAppTransitionStartRect(WindowContainer container, Rect rect) {
+        AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(
+                container.hashCode());
         if (spec == null) {
             spec = mDefaultNextAppTransitionAnimationSpec;
         }
         if (spec == null || spec.rect == null) {
-            Slog.e(TAG, "Starting rect for task: " + taskId + " requested, but not available",
-                    new Throwable());
+            Slog.e(TAG, "Starting rect for container: " + container
+                            + " requested, but not available", new Throwable());
             rect.setEmpty();
         } else {
             rect.set(spec.rect);
@@ -1065,7 +1067,7 @@
      * when a thumbnail is specified with the pending animation override.
      */
     Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, @Nullable Rect contentInsets,
-            GraphicBuffer thumbnailHeader, final int taskId, int uiMode, int orientation) {
+            GraphicBuffer thumbnailHeader, WindowContainer container, int uiMode, int orientation) {
         Animation a;
         final int thumbWidthI = thumbnailHeader.getWidth();
         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
@@ -1073,7 +1075,7 @@
         final int appWidth = appRect.width();
 
         float scaleW = appWidth / thumbWidth;
-        getNextAppTransitionStartRect(taskId, mTmpRect);
+        getNextAppTransitionStartRect(container, mTmpRect);
         final float fromX;
         float fromY;
         final float toX;
@@ -1226,7 +1228,7 @@
     Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState,
             int uiMode, int orientation, int transit, Rect containingFrame, Rect contentInsets,
             @Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean freeform,
-            int taskId) {
+            WindowContainer container) {
         Animation a;
         final int appWidth = containingFrame.width();
         final int appHeight = containingFrame.height();
@@ -1244,10 +1246,10 @@
                 final boolean scaleUp = thumbTransitState == THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
                 if (freeform && scaleUp) {
                     a = createAspectScaledThumbnailEnterFreeformAnimationLocked(
-                            containingFrame, surfaceInsets, taskId);
+                            containingFrame, surfaceInsets, container);
                 } else if (freeform) {
                     a = createAspectScaledThumbnailExitFreeformAnimationLocked(
-                            containingFrame, surfaceInsets, taskId);
+                            containingFrame, surfaceInsets, container);
                 } else {
                     AnimationSet set = new AnimationSet(true);
 
@@ -1359,15 +1361,15 @@
     }
 
     private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame,
-            @Nullable Rect surfaceInsets, int taskId) {
-        getNextAppTransitionStartRect(taskId, mTmpRect);
+            @Nullable Rect surfaceInsets, WindowContainer container) {
+        getNextAppTransitionStartRect(container, mTmpRect);
         return createAspectScaledThumbnailFreeformAnimationLocked(mTmpRect, frame, surfaceInsets,
                 true);
     }
 
     private Animation createAspectScaledThumbnailExitFreeformAnimationLocked(Rect frame,
-            @Nullable Rect surfaceInsets, int taskId) {
-        getNextAppTransitionStartRect(taskId, mTmpRect);
+            @Nullable Rect surfaceInsets, WindowContainer container) {
+        getNextAppTransitionStartRect(container, mTmpRect);
         return createAspectScaledThumbnailFreeformAnimationLocked(frame, mTmpRect, surfaceInsets,
                 false);
     }
@@ -1469,10 +1471,10 @@
      * leaving, and the activity that is entering.
      */
     Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, Rect containingFrame,
-            int transit, int taskId) {
+            int transit, WindowContainer container) {
         final int appWidth = containingFrame.width();
         final int appHeight = containingFrame.height();
-        final GraphicBuffer thumbnailHeader = getAppTransitionThumbnailHeader(taskId);
+        final GraphicBuffer thumbnailHeader = getAppTransitionThumbnailHeader(container);
         Animation a;
         getDefaultNextAppTransitionStartRect(mTmpRect);
         final int thumbWidthI = thumbnailHeader != null ? thumbnailHeader.getWidth() : appWidth;
@@ -1615,7 +1617,7 @@
     Animation loadAnimation(LayoutParams lp, int transit, boolean enter, int uiMode,
             int orientation, Rect frame, Rect displayFrame, Rect insets,
             @Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean isVoiceInteraction,
-            boolean freeform, int taskId) {
+            boolean freeform, WindowContainer container) {
         Animation a;
         if (isKeyguardGoingAwayTransit(transit) && enter) {
             a = loadKeyguardExitAnimation(transit);
@@ -1679,7 +1681,7 @@
             mNextAppTransitionScaleUp =
                     (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
             a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
-                    frame, transit, taskId);
+                    frame, transit, container);
             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
                     "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b "
                             + "Callers=%s",
@@ -1692,7 +1694,7 @@
                     (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
             a = createAspectScaledThumbnailEnterExitAnimationLocked(
                     getThumbnailTransitionState(enter), uiMode, orientation, transit, frame,
-                    insets, surfaceInsets, stableInsets, freeform, taskId);
+                    insets, surfaceInsets, stableInsets, freeform, container);
             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
                     "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b "
                             + "Callers=%s",
@@ -1895,7 +1897,11 @@
                 for (int i = 0; i < specs.length; i++) {
                     AppTransitionAnimationSpec spec = specs[i];
                     if (spec != null) {
-                        mNextAppTransitionAnimationsSpecs.put(spec.taskId, spec);
+                        final WindowContainer container = findTask(spec.taskId);
+                        if (container == null) {
+                            continue;
+                        }
+                        mNextAppTransitionAnimationsSpecs.put(container.hashCode(), spec);
                         if (i == 0) {
                             // In full screen mode, the transition code depends on the default spec
                             // to be set.
@@ -1912,6 +1918,19 @@
         }
     }
 
+    private Task findTask(int taskId) {
+        if (taskId < 0) {
+            return null;
+        }
+        ArrayList<Task> tasks = new ArrayList<>();
+        mDisplayContent.forAllTasks(task -> {
+            if (task.mTaskId == taskId) {
+                tasks.add(task);
+            }
+        });
+        return tasks.size() == 1 ? tasks.get(0) : null;
+    }
+
     void overridePendingAppTransitionMultiThumbFuture(
             IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback callback,
             boolean scaleUp) {
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 3bda0c2..bef6af3 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -410,7 +410,7 @@
             ActivityRecord activity = apps.valueAt(i);
             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now changing app %s", activity);
             activity.cancelAnimationOnly();
-            activity.applyAnimationLocked(null, transit, true, false);
+            activity.applyAnimation(null, transit, true, false);
             activity.updateReportedVisibilityLocked();
             mService.openSurfaceTransaction();
             try {
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 300ee1d..8b4f7cc 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -39,11 +39,15 @@
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.os.IBinder;
 import android.util.proto.ProtoOutputStream;
+import android.view.IWindowContainer;
+import android.view.SurfaceControl;
 
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 
 /**
@@ -102,6 +106,11 @@
     // Return value from {@link setBounds} indicating the size of the override bounds changed.
     static final int BOUNDS_CHANGE_SIZE = 1 << 1;
 
+    /**
+     * Used as a unique, cross-process identifier for this Container. It also serves a minimal
+     * interface to other processes.
+     */
+    RemoteToken mRemoteToken = null;
 
     /**
      * Returns full configuration applied to this configuration container.
@@ -540,7 +549,7 @@
         return sameWindowingMode;
     }
 
-    public void registerConfigurationChangeListener(ConfigurationContainerListener listener) {
+    void registerConfigurationChangeListener(ConfigurationContainerListener listener) {
         if (mChangeListeners.contains(listener)) {
             return;
         }
@@ -548,7 +557,7 @@
         listener.onRequestedOverrideConfigurationChanged(mResolvedOverrideConfiguration);
     }
 
-    public void unregisterConfigurationChangeListener(ConfigurationContainerListener listener) {
+    void unregisterConfigurationChangeListener(ConfigurationContainerListener listener) {
         mChangeListeners.remove(listener);
     }
 
@@ -560,13 +569,12 @@
     /**
      * Must be called when new parent for the container was set.
      */
-    void onParentChanged() {
-        final ConfigurationContainer parent = getParent();
+    void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
         // Removing parent usually means that we've detached this entity to destroy it or to attach
         // to another parent. In both cases we don't need to update the configuration now.
-        if (parent != null) {
+        if (newParent != null) {
             // Update full configuration of this container and all its children.
-            onConfigurationChanged(parent.mFullConfiguration);
+            onConfigurationChanged(newParent.mFullConfiguration);
             // Update merged override configuration of this container and all its children.
             onMergedOverrideConfigurationChanged();
         }
@@ -635,4 +643,37 @@
     abstract protected E getChildAt(int index);
 
     abstract protected ConfigurationContainer getParent();
+
+    // TODO: Consider moving to WindowContainer once hierarchies and Task/Stack are merged.
+    static class RemoteToken extends IWindowContainer.Stub {
+        final WeakReference<ConfigurationContainer> mWeakRef;
+
+        RemoteToken(ConfigurationContainer container) {
+            mWeakRef = new WeakReference<>(container);
+        }
+
+        ConfigurationContainer getContainer() {
+            return mWeakRef.get();
+        }
+
+        static RemoteToken fromBinder(IBinder binder) {
+            return (RemoteToken) binder;
+        }
+
+        @Override
+        public SurfaceControl getLeash() {
+            throw new RuntimeException("Not implemented");
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("RemoteToken{");
+            sb.append(Integer.toHexString(System.identityHashCode(this)));
+            sb.append(' ');
+            sb.append(mWeakRef.get());
+            sb.append('}');
+            return sb.toString();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index aa0b68b..89568eb 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -106,6 +106,8 @@
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
 import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
+import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
@@ -2363,7 +2365,7 @@
 
     @Override
     void removeIfPossible() {
-        if (isAnimating()) {
+        if (isAnimating(TRANSITION | PARENTS)) {
             mDeferredRemoval = true;
             return;
         }
@@ -3165,13 +3167,15 @@
                 // to look at all windows below the current target that are in this app, finding the
                 // highest visible one in layering.
                 WindowState highestTarget = null;
-                if (activity.isSelfAnimating()) {
+                if (activity.isAnimating(TRANSITION)) {
                     highestTarget = activity.getHighestAnimLayerWindow(curTarget);
                 }
 
                 if (highestTarget != null) {
-                    if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, mAppTransition + " " + highestTarget
-                            + " animating=" + highestTarget.isAnimating());
+                    if (DEBUG_INPUT_METHOD) {
+                        Slog.v(TAG_WM, mAppTransition + " " + highestTarget + " animating="
+                                + highestTarget.isAnimating(TRANSITION | PARENTS));
+                    }
 
                     if (mAppTransition.isTransitionSet()) {
                         // If we are currently setting up for an animation, hold everything until we
@@ -4322,7 +4326,7 @@
                     // The split screen divider anchor is located above the split screen window.
                     layerForSplitScreenDividerAnchor = layer++;
                 }
-                if (s.isTaskAnimating() || s.isAppAnimating()) {
+                if (s.isTaskAnimating() || s.isAppTransitioning()) {
                     // The animation layer is located above the highest animating stack and no
                     // higher.
                     layerForAnimationLayer = layer++;
@@ -4359,9 +4363,9 @@
         }
 
         @Override
-        void onParentChanged() {
+        void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
             if (getParent() != null) {
-                super.onParentChanged(() -> {
+                super.onParentChanged(newParent, oldParent, () -> {
                     mAppAnimationLayer = makeChildSurface(null)
                             .setName("animationLayer")
                             .build();
@@ -4381,7 +4385,7 @@
                             .show(mSplitScreenDividerAnchor);
                 });
             } else {
-                super.onParentChanged();
+                super.onParentChanged(newParent, oldParent);
                 mWmService.mTransactionFactory.get()
                         .remove(mAppAnimationLayer)
                         .remove(mBoostedAppAnimationLayer)
@@ -4611,7 +4615,7 @@
     }
 
     @Override
-    void onParentChanged() {
+    void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
         // Since we are the top of the SurfaceControl hierarchy here
         // we create the root surfaces explicitly rather than chaining
         // up as the default implementation in onParentChanged does. So we
@@ -4651,7 +4655,8 @@
         // so it get's layered above the starting window.
         if (imeTarget != null
                 && !(imeTarget.mActivityRecord != null && imeTarget.mActivityRecord.hasStartingWindow())
-                && (!(imeTarget.inSplitScreenWindowingMode() || imeTarget.mToken.isAppAnimating())
+                && (!(imeTarget.inSplitScreenWindowingMode()
+                             || imeTarget.mToken.isAppTransitioning())
                 && (imeTarget.getSurfaceControl() != null))) {
             mImeWindowsContainers.assignRelativeLayer(t, imeTarget.getSurfaceControl(),
                     // TODO: We need to use an extra level on the app surface to ensure
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 2772483..6e238b3 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -876,6 +876,8 @@
                 if (canToastShowWhenLocked(callingPid)) {
                     attrs.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
                 }
+                // Toasts can't be clickable
+                attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
                 break;
         }
 
@@ -1918,10 +1920,18 @@
             vf.set(displayFrames.mStable);
 
             if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
-                cf.bottom = displayFrames.mContent.bottom;
+                // cf.bottom should not be below the stable bottom, or the content might be obscured
+                // by the navigation bar.
+                if (cf.bottom > displayFrames.mContent.bottom) {
+                    cf.bottom = displayFrames.mContent.bottom;
+                }
             } else {
-                cf.bottom = displayFrames.mDock.bottom;
-                vf.bottom = displayFrames.mContent.bottom;
+                if (cf.bottom > displayFrames.mDock.bottom) {
+                    cf.bottom = displayFrames.mDock.bottom;
+                }
+                if (vf.bottom > displayFrames.mContent.bottom) {
+                    vf.bottom = displayFrames.mContent.bottom;
+                }
             }
         } else {
             dcf.set(displayFrames.mSystem);
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index bc95481..11f09d0 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -56,8 +56,6 @@
         if (mIsImeLayoutDrawn && mShowImeRunner != null) {
             // Show IME if InputMethodService requested to be shown and it's layout has finished.
             mShowImeRunner.run();
-            mIsImeLayoutDrawn = false;
-            mShowImeRunner = null;
         }
     }
 
@@ -74,10 +72,19 @@
                 mDisplayContent.mInputMethodTarget.showInsets(
                         WindowInsets.Type.ime(), true /* fromIme */);
             }
-            mImeTargetFromIme = null;
+            abortShowImePostLayout();
         };
     }
 
+    /**
+     * Abort any pending request to show IME post layout.
+     */
+    void abortShowImePostLayout() {
+        mImeTargetFromIme = null;
+        mIsImeLayoutDrawn = false;
+        mShowImeRunner = null;
+    }
+
     private boolean isImeTargetFromDisplayContentAndImeSame() {
         // IMMS#mLastImeTargetWindow always considers focused window as
         // IME target, however DisplayContent#computeImeTarget() can compute
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 7f9e76b..1ebbb02 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -4,6 +4,7 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 
+import static com.android.server.wm.ActivityRecord.INVALID_PID;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -14,6 +15,7 @@
 import android.os.RemoteException;
 import android.util.Slog;
 import android.view.IWindow;
+import android.view.InputApplicationHandle;
 import android.view.KeyEvent;
 import android.view.WindowManager;
 
@@ -80,7 +82,8 @@
      * Called by the InputManager.
      */
     @Override
-    public long notifyANR(IBinder token, String reason) {
+    public long notifyANR(InputApplicationHandle inputApplicationHandle,
+            IBinder token, String reason) {
         ActivityRecord activity = null;
         WindowState windowState = null;
         boolean aboveSystem = false;
@@ -93,6 +96,10 @@
                 }
             }
 
+            if (activity == null && inputApplicationHandle != null) {
+                activity = ActivityRecord.forTokenLocked(inputApplicationHandle.token);
+            }
+
             if (windowState != null) {
                 Slog.i(TAG_WM, "Input event dispatching timed out "
                         + "sending to " + windowState.mAttrs.getTitle()
@@ -122,7 +129,7 @@
             // Notify the activity manager about the timeout and let it decide whether
             // to abort dispatching or keep waiting.
             final boolean abort = activity.keyDispatchingTimedOut(reason,
-                    windowState.mSession.mPid);
+                    (windowState != null) ? windowState.mSession.mPid : INVALID_PID);
             if (!abort) {
                 // The activity manager declined to abort dispatching.
                 // Wait a bit longer and timeout again later.
diff --git a/services/core/java/com/android/server/wm/PolicyControl.java b/services/core/java/com/android/server/wm/PolicyControl.java
index 4c8ce9e..0f92bc8 100644
--- a/services/core/java/com/android/server/wm/PolicyControl.java
+++ b/services/core/java/com/android/server/wm/PolicyControl.java
@@ -26,6 +26,8 @@
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.io.PrintWriter;
 import java.io.StringWriter;
 
@@ -51,7 +53,8 @@
     private static final String TAG = "PolicyControl";
     private static final boolean DEBUG = false;
 
-    private static final String NAME_IMMERSIVE_FULL = "immersive.full";
+    @VisibleForTesting
+    static final String NAME_IMMERSIVE_FULL = "immersive.full";
     private static final String NAME_IMMERSIVE_STATUS = "immersive.status";
     private static final String NAME_IMMERSIVE_NAVIGATION = "immersive.navigation";
     private static final String NAME_IMMERSIVE_PRECONFIRMATIONS = "immersive.preconfirms";
@@ -67,15 +70,19 @@
                 : (attrs.systemUiVisibility | attrs.subtreeSystemUiVisibility);
         if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
             vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
-                    | View.SYSTEM_UI_FLAG_FULLSCREEN
-                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+                    | View.SYSTEM_UI_FLAG_FULLSCREEN;
+            if (attrs.isFullscreen()) {
+                vis |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+            }
             vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                     | View.STATUS_BAR_TRANSLUCENT);
         }
         if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)) {
             vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
-                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                     | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+            if (attrs.isFullscreen()) {
+                vis |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+            }
             vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                     | View.NAVIGATION_BAR_TRANSLUCENT);
         }
@@ -144,7 +151,8 @@
         }
     }
 
-    private static void setFilters(String value) {
+    @VisibleForTesting
+    static void setFilters(String value) {
         if (DEBUG) Slog.d(TAG, "setFilters: " + value);
         sImmersiveStatusFilter = null;
         sImmersiveNavigationFilter = null;
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index b7d25c3..2dae126 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -452,7 +452,7 @@
                 .setCallingUid(mRecentsUid)
                 .setCallingPackage(mRecentsComponent.getPackageName())
                 .setActivityOptions(new SafeActivityOptions(options))
-                .setMayWait(mUserId)
+                .setUserId(mUserId)
                 .execute();
     }
 
diff --git a/services/core/java/com/android/server/wm/RefreshRatePolicy.java b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
index 0c0cf92..e0a7b18 100644
--- a/services/core/java/com/android/server/wm/RefreshRatePolicy.java
+++ b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
@@ -16,6 +16,9 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
+
 import android.util.ArraySet;
 import android.view.Display.Mode;
 import android.view.DisplayInfo;
@@ -67,7 +70,7 @@
 
         // If app is animating, it's not able to control refresh rate because we want the animation
         // to run in default refresh rate.
-        if (w.isAnimating()) {
+        if (w.isAnimating(TRANSITION | PARENTS)) {
             return 0;
         }
 
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index c23ffd9..efd1241 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -41,7 +41,6 @@
 import com.android.server.protolog.ProtoLogImpl;
 import com.android.server.protolog.common.ProtoLog;
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
-import com.android.server.wm.utils.InsetUtils;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -76,20 +75,20 @@
     }
 
     /**
-     * Creates an animation record for each individual {@link ActivityRecord}.
+     * Creates an animation record for each individual {@link WindowContainer}.
      *
-     * @param activity The app to animate.
+     * @param windowContainer The windows to animate.
      * @param position The position app bounds, in screen coordinates.
      * @param stackBounds The stack bounds of the app relative to position.
      * @param startBounds The stack bounds before the transition, in screen coordinates
      * @return The record representing animation(s) to run on the app.
      */
-    RemoteAnimationRecord createRemoteAnimationRecord(ActivityRecord activity, Point position,
-            Rect stackBounds, Rect startBounds) {
-        ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAnimationAdapter(): token=%s",
-                activity);
+    RemoteAnimationRecord createRemoteAnimationRecord(WindowContainer windowContainer,
+            Point position, Rect stackBounds, Rect startBounds) {
+        ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAnimationAdapter(): container=%s",
+                windowContainer);
         final RemoteAnimationRecord adapters =
-                new RemoteAnimationRecord(activity, position, stackBounds, startBounds);
+                new RemoteAnimationRecord(windowContainer, position, stackBounds, startBounds);
         mPendingAnimations.add(adapters);
         return adapters;
     }
@@ -169,11 +168,12 @@
             final RemoteAnimationRecord wrappers = mPendingAnimations.get(i);
             final RemoteAnimationTarget target = wrappers.createRemoteAnimationTarget();
             if (target != null) {
-                ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tAdd token=%s", wrappers.mActivityRecord);
+                ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tAdd container=%s",
+                        wrappers.mWindowContainer);
                 targets.add(target);
             } else {
-                ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tRemove token=%s",
-                        wrappers.mActivityRecord);
+                ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tRemove container=%s",
+                        wrappers.mWindowContainer);
 
                 // We can't really start an animation but we still need to make sure to finish the
                 // pending animation that was started by SurfaceAnimator
@@ -228,7 +228,8 @@
                                 .onAnimationFinished(adapters.mThumbnailAdapter);
                     }
                     mPendingAnimations.remove(i);
-                    ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tapp=%s", adapters.mActivityRecord);
+                    ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tcontainer=%s",
+                            adapters.mWindowContainer);
                 }
 
                 for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) {
@@ -332,7 +333,7 @@
     };
 
     /**
-     * Contains information about a remote-animation for one AppWindowToken. This keeps track of,
+     * Contains information about a remote-animation for one WindowContainer. This keeps track of,
      * potentially, multiple animating surfaces (AdapterWrappers) associated with one
      * Window/Transition. For example, a change transition has an adapter controller for the
      * main window and an adapter controlling the start-state snapshot.
@@ -345,12 +346,12 @@
         RemoteAnimationAdapterWrapper mAdapter;
         RemoteAnimationAdapterWrapper mThumbnailAdapter = null;
         RemoteAnimationTarget mTarget;
-        final ActivityRecord mActivityRecord;
+        final WindowContainer mWindowContainer;
         final Rect mStartBounds;
 
-        RemoteAnimationRecord(ActivityRecord activityRecord, Point endPos, Rect endBounds,
+        RemoteAnimationRecord(WindowContainer windowContainer, Point endPos, Rect endBounds,
                 Rect startBounds) {
-            mActivityRecord = activityRecord;
+            mWindowContainer = windowContainer;
             mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, endBounds);
             if (startBounds != null) {
                 mStartBounds = new Rect(startBounds);
@@ -366,31 +367,20 @@
         }
 
         RemoteAnimationTarget createRemoteAnimationTarget() {
-            final Task task = mActivityRecord.getTask();
-            final WindowState mainWindow = mActivityRecord.findMainWindow();
-            if (task == null || mainWindow == null || mAdapter == null
+            if (mAdapter == null
                     || mAdapter.mCapturedFinishCallback == null
                     || mAdapter.mCapturedLeash == null) {
                 return null;
             }
-            final Rect insets = new Rect();
-            mainWindow.getContentInsets(insets);
-            InsetUtils.addInsets(insets, mActivityRecord.getLetterboxInsets());
-            mTarget = new RemoteAnimationTarget(task.mTaskId, getMode(),
-                    mAdapter.mCapturedLeash, !mActivityRecord.fillsParent(),
-                    mainWindow.mWinAnimator.mLastClipRect, insets,
-                    mActivityRecord.getPrefixOrderIndex(), mAdapter.mPosition,
-                    mAdapter.mStackBounds, task.getWindowConfiguration(), false /*isNotInRecents*/,
-                    mThumbnailAdapter != null ? mThumbnailAdapter.mCapturedLeash : null,
-                    mStartBounds);
+            mTarget = mWindowContainer.createRemoteAnimationTarget(this);
             return mTarget;
         }
 
-        private int getMode() {
-            final DisplayContent dc = mActivityRecord.getDisplayContent();
-            if (dc.mOpeningApps.contains(mActivityRecord)) {
+        int getMode() {
+            final DisplayContent dc = mWindowContainer.getDisplayContent();
+            if (dc.mOpeningApps.contains(mWindowContainer)) {
                 return RemoteAnimationTarget.MODE_OPENING;
-            } else if (dc.mChangingApps.contains(mActivityRecord)) {
+            } else if (dc.mChangingApps.contains(mWindowContainer)) {
                 return RemoteAnimationTarget.MODE_CHANGING;
             } else {
                 return RemoteAnimationTarget.MODE_CLOSING;
@@ -398,12 +388,12 @@
         }
     }
 
-    private class RemoteAnimationAdapterWrapper implements AnimationAdapter {
+    class RemoteAnimationAdapterWrapper implements AnimationAdapter {
         private final RemoteAnimationRecord mRecord;
         SurfaceControl mCapturedLeash;
         private OnAnimationFinishedCallback mCapturedFinishCallback;
-        private final Point mPosition = new Point();
-        private final Rect mStackBounds = new Rect();
+        final Point mPosition = new Point();
+        final Rect mStackBounds = new Rect();
 
         RemoteAnimationAdapterWrapper(RemoteAnimationRecord record, Point position,
                 Rect stackBounds) {
@@ -423,7 +413,7 @@
             ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation");
 
             // Restore z-layering, position and stack crop until client has a chance to modify it.
-            t.setLayer(animationLeash, mRecord.mActivityRecord.getPrefixOrderIndex());
+            t.setLayer(animationLeash, mRecord.mWindowContainer.getPrefixOrderIndex());
             if (mRecord.mStartBounds != null) {
                 t.setPosition(animationLeash, mRecord.mStartBounds.left, mRecord.mStartBounds.top);
                 t.setWindowCrop(animationLeash, mRecord.mStartBounds.width(),
@@ -464,7 +454,7 @@
 
         @Override
         public void dump(PrintWriter pw, String prefix) {
-            pw.print(prefix); pw.print("token="); pw.println(mRecord.mActivityRecord);
+            pw.print(prefix); pw.print("container="); pw.println(mRecord.mWindowContainer);
             if (mRecord.mTarget != null) {
                 pw.print(prefix); pw.println("Target:");
                 mRecord.mTarget.dump(pw, prefix + "  ");
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 9db6dc2..51a3e720 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -1154,7 +1154,7 @@
                 // activity is started and resumed, and no recursion occurs.
                 final ActivityStack focusedStack = display.getFocusedStack();
                 if (focusedStack != null) {
-                    focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);
+                    result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 17f5abd..f5d3aff 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -787,7 +787,7 @@
                 }
             }
 
-            if (curDisplay.mAppTransition.isRunning() && !curDisplay.isAppAnimating()) {
+            if (curDisplay.mAppTransition.isRunning() && !curDisplay.isAppTransitioning()) {
                 // We have finished the animation of an app transition. To do this, we have
                 // delayed a lot of operations like showing and hiding apps, moving apps in
                 // Z-order, etc.
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 1db3149f..634990b 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -28,13 +28,14 @@
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
 import static com.android.server.wm.TaskProto.APP_WINDOW_TOKENS;
 import static com.android.server.wm.TaskProto.BOUNDS;
-import static com.android.server.wm.TaskProto.DEFER_REMOVAL;
 import static com.android.server.wm.TaskProto.DISPLAYED_BOUNDS;
 import static com.android.server.wm.TaskProto.FILLS_PARENT;
 import static com.android.server.wm.TaskProto.ID;
 import static com.android.server.wm.TaskProto.SURFACE_HEIGHT;
 import static com.android.server.wm.TaskProto.SURFACE_WIDTH;
 import static com.android.server.wm.TaskProto.WINDOW_CONTAINER;
+import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -50,6 +51,7 @@
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
+import android.view.RemoteAnimationTarget;
 import android.view.Surface;
 import android.view.SurfaceControl;
 
@@ -67,7 +69,6 @@
     final int mTaskId;
     /* User for which this task was created. */
     final int mUserId;
-    private boolean mDeferRemoval = false;
 
     final Rect mPreparedFrozenBounds = new Rect();
     final Configuration mPreparedFrozenMergedConfig = new Configuration();
@@ -176,14 +177,18 @@
     void addChild(ActivityRecord child, int position) {
         position = getAdjustedAddPosition(position);
         super.addChild(child, position);
-        mDeferRemoval = false;
+
+        // Inform the TaskRecord side of the child addition
+        // TODO(task-unify): Will be removed after task unification.
+        if (mTaskRecord != null) {
+            mTaskRecord.onChildAdded(child, position);
+        }
     }
 
     @Override
     void positionChildAt(int position, ActivityRecord child, boolean includingParents) {
         position = getAdjustedAddPosition(position);
         super.positionChildAt(position, child, includingParents);
-        mDeferRemoval = false;
     }
 
     private boolean hasWindowsAlive() {
@@ -197,16 +202,17 @@
 
     @VisibleForTesting
     boolean shouldDeferRemoval() {
-        // TODO: This should probably return false if mChildren.isEmpty() regardless if the stack
-        // is animating...
-        return hasWindowsAlive() && mStack.isSelfOrChildAnimating();
+        if (mChildren.isEmpty()) {
+            // No reason to defer removal of a Task that doesn't have any child.
+            return false;
+        }
+        return hasWindowsAlive() && mStack.isAnimating(TRANSITION | CHILDREN);
     }
 
     @Override
     void removeIfPossible() {
         if (shouldDeferRemoval()) {
             if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
-            mDeferRemoval = true;
             return;
         }
         removeImmediately();
@@ -216,7 +222,6 @@
     void removeImmediately() {
         if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
         EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeTask");
-        mDeferRemoval = false;
         if (mTaskRecord != null) {
             mTaskRecord.unregisterConfigurationChangeListener(this);
         }
@@ -266,8 +271,8 @@
     }
 
     @Override
-    void onParentChanged() {
-        super.onParentChanged();
+    void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
+        super.onParentChanged(newParent, oldParent);
 
         // Update task bounds if needed.
         adjustBoundsForDisplayChangeIfNeeded(getDisplayContent());
@@ -290,11 +295,18 @@
 
         super.removeChild(child);
 
+        // Inform the TaskRecord side of the child removal
+        // TODO(task-unify): Will be removed after task unification.
+        if (mTaskRecord != null) {
+            mTaskRecord.onChildRemoved(child);
+        }
+
+        // TODO(task-unify): Need to make this account for what we are doing in
+        // ActivityRecord.removeFromHistory so that the task isn't removed in some situations when
+        // we unify task level.
         if (mChildren.isEmpty()) {
             EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeActivity: last activity");
-            if (mDeferRemoval) {
-                removeIfPossible();
-            }
+            removeIfPossible();
         }
     }
 
@@ -459,6 +471,17 @@
         }
     }
 
+    @Override
+    void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
+            Rect outSurfaceInsets) {
+        final WindowState windowState = getTopVisibleAppMainWindow();
+        if (windowState != null) {
+            windowState.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
+        } else {
+            super.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
+        }
+    }
+
     /**
      * Calculate the maximum visible area of this task. If the task has only one app,
      * the result will be visible frame of that app. If the task has more than one apps,
@@ -635,6 +658,18 @@
         return getAppAnimationLayer(ANIMATION_LAYER_HOME);
     }
 
+    boolean shouldAnimate() {
+        // Don't animate while the task runs recents animation but only if we are in the mode
+        // where we cancel with deferred screenshot, which means that the controller has
+        // transformed the task.
+        final RecentsAnimationController controller = mWmService.getRecentsAnimationController();
+        if (controller != null && controller.isAnimatingTask(this)
+                && controller.shouldDeferCancelUntilNextTransition()) {
+            return false;
+        }
+        return true;
+    }
+
     @Override
     SurfaceControl.Builder makeSurface() {
         return super.makeSurface().setMetadata(METADATA_TASK_ID, mTaskId);
@@ -650,6 +685,22 @@
         return false;
     }
 
+    /**
+     * @return {@code true} if changing app transition is running.
+     */
+    @Override
+    boolean isChangingAppTransition() {
+        final ActivityRecord activity = getTopVisibleActivity();
+        return activity != null && getDisplayContent().mChangingApps.contains(activity);
+    }
+
+    @Override
+    RemoteAnimationTarget createRemoteAnimationTarget(
+            RemoteAnimationController.RemoteAnimationRecord record) {
+        final ActivityRecord activity = getTopVisibleActivity();
+        return activity != null ? activity.createRemoteAnimationTarget(record) : null;
+    }
+
     WindowState getTopVisibleAppMainWindow() {
         final ActivityRecord activity = getTopVisibleActivity();
         return activity != null ? activity.findMainWindow() : null;
@@ -745,7 +796,7 @@
 
     @Override
     public String toString() {
-        return "{taskId=" + mTaskId + " appTokens=" + mChildren + " mdr=" + mDeferRemoval + "}";
+        return "{taskId=" + mTaskId + " appTokens=" + mChildren + "}";
     }
 
     String getName() {
@@ -792,7 +843,6 @@
         proto.write(FILLS_PARENT, matchParentBounds());
         getBounds().writeToProto(proto, BOUNDS);
         mOverrideDisplayedBounds.writeToProto(proto, DISPLAYED_BOUNDS);
-        proto.write(DEFER_REMOVAL, mDeferRemoval);
         proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth());
         proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight());
         proto.end(token);
@@ -805,7 +855,6 @@
 
         pw.println(prefix + "taskId=" + mTaskId);
         pw.println(doublePrefix + "mBounds=" + getBounds().toShortString());
-        pw.println(doublePrefix + "mdr=" + mDeferRemoval);
         pw.println(doublePrefix + "appTokens=" + mChildren);
         pw.println(doublePrefix + "mDisplayedBounds=" + mOverrideDisplayedBounds.toShortString());
 
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 9712277..31145de 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -43,10 +43,8 @@
 import android.app.ActivityOptions;
 import android.app.WindowConfiguration;
 import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
-import android.os.Build;
 import android.util.Slog;
 import android.view.Gravity;
 import android.view.View;
@@ -65,15 +63,6 @@
     private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskLaunchParamsModifier" : TAG_ATM;
     private static final boolean DEBUG = false;
 
-    // A mask for SUPPORTS_SCREEN that indicates the activity supports resize.
-    private static final int SUPPORTS_SCREEN_RESIZEABLE_MASK =
-            ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES
-                    | ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS
-                    | ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS
-                    | ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS
-                    | ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES
-                    | ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
-
     // Screen size of Nexus 5x
     private static final int DEFAULT_PORTRAIT_PHONE_WIDTH_DP = 412;
     private static final int DEFAULT_PORTRAIT_PHONE_HEIGHT_DP = 732;
@@ -253,10 +242,9 @@
         if (display.inFreeformWindowingMode()) {
             if (launchMode == WINDOWING_MODE_PINNED) {
                 if (DEBUG) appendLog("picture-in-picture");
-            } else if (isTaskForcedMaximized(root)) {
-                // We're launching an activity that probably can't handle resizing nicely, so force
-                // it to be maximized even someone suggests launching it in freeform using launch
-                // options.
+            } else if (!mSupervisor.mService.mSizeCompatFreeform && !root.isResizeable()) {
+                // We're launching an activity in size-compat mode and they aren't allowed in
+                // freeform, so force it to be maximized.
                 launchMode = WINDOWING_MODE_FULLSCREEN;
                 outParams.mBounds.setEmpty();
                 if (DEBUG) appendLog("forced-maximize");
@@ -460,28 +448,6 @@
     }
 
     /**
-     * Returns if task is forced to maximize.
-     *
-     * There are several cases where we force a task to maximize:
-     * 1) Root activity is targeting pre-Donut, which by default can't handle multiple screen
-     *    densities, so resizing will likely cause issues;
-     * 2) Root activity doesn't declare any flag that it supports any screen density, so resizing
-     *    may also cause issues;
-     * 3) Root activity is not resizeable, for which we shouldn't allow user resize it.
-     *
-     * @param root the root activity to check against.
-     * @return {@code true} if it should be forced to maximize; {@code false} otherwise.
-     */
-    private boolean isTaskForcedMaximized(@NonNull ActivityRecord root) {
-        if (root.info.applicationInfo.targetSdkVersion < Build.VERSION_CODES.DONUT
-                || (root.info.applicationInfo.flags & SUPPORTS_SCREEN_RESIZEABLE_MASK) == 0) {
-            return true;
-        }
-
-        return !root.isResizeable();
-    }
-
-    /**
      * Resolves activity requested orientation to 4 categories:
      * 1) {@link ActivityInfo#SCREEN_ORIENTATION_LOCKED} indicating app wants to lock down
      *    orientation;
diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java
index ed07f30..e1123fa 100644
--- a/services/core/java/com/android/server/wm/TaskPositioningController.java
+++ b/services/core/java/com/android/server/wm/TaskPositioningController.java
@@ -126,6 +126,11 @@
             synchronized (mService.mGlobalLock) {
                 final Task task = displayContent.findTaskForResizePoint(x, y);
                 if (task != null) {
+                    if (!task.isResizeable()) {
+                        // The task is not resizable, so don't do anything when the user drags the
+                        // the resize handles.
+                        return;
+                    }
                     if (!startPositioningLocked(task.getTopVisibleAppMainWindow(), true /*resize*/,
                             task.preserveOrientationOnResize(), x, y)) {
                         return;
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 299b32c..6920d9d 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -68,10 +68,12 @@
 import static com.android.server.am.TaskRecordProto.STACK_ID;
 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
 import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
+import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
 import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING_TO_TOP;
 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
@@ -82,6 +84,7 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
@@ -126,6 +129,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.util.XmlUtils;
+import com.android.server.protolog.common.ProtoLog;
 import com.android.server.wm.ActivityStack.ActivityState;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -373,6 +377,7 @@
             IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
         mAtmService = atmService;
         mTaskId = _taskId;
+        mRemoteToken = new RemoteToken(this);
         affinityIntent = _affinityIntent;
         affinity = _affinity;
         rootAffinity = _rootAffinity;
@@ -519,18 +524,7 @@
         mAtmService.deferWindowLayout();
 
         try {
-            if (!isResizeable()) {
-                Slog.w(TAG, "resizeTask: task " + this + " not resizeable.");
-                return true;
-            }
-
-            // If this is a forced resize, let it go through even if the bounds is not changing,
-            // as we might need a relayout due to surface size change (to/from fullscreen).
             final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
-            if (equivalentRequestedOverrideBounds(bounds) && !forced) {
-                // Nothing to do here...
-                return true;
-            }
 
             if (mTask == null) {
                 // Task doesn't exist in window manager yet (e.g. was restored from recents).
@@ -980,6 +974,7 @@
      * Must be used for setting parent stack because it performs configuration updates.
      * Must be called after adding task as a child to the stack.
      */
+    // TODO(task-unify): Remove or rework after task level unification.
     void setStack(ActivityStack stack) {
         if (stack != null && !stack.isInStackLocked(this)) {
             throw new IllegalStateException("Task must be added as a Stack child first.");
@@ -1004,7 +999,7 @@
             }
         }
 
-        onParentChanged();
+        onParentChanged(mStack, oldStack);
     }
 
     /**
@@ -1030,8 +1025,9 @@
     }
 
     @Override
-    protected void onParentChanged() {
-        super.onParentChanged();
+    protected void onParentChanged(
+            ConfigurationContainer newParent, ConfigurationContainer oldParent) {
+        super.onParentChanged(newParent, oldParent);
         mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
     }
 
@@ -1226,10 +1222,6 @@
         updateEffectiveIntent();
     }
 
-    void addActivityToTop(ActivityRecord r) {
-        addActivityAtIndex(getChildCount(), r);
-    }
-
     @Override
     /*@WindowConfiguration.ActivityType*/
     public int getActivityType() {
@@ -1240,18 +1232,11 @@
         return getChildAt(0).getActivityType();
     }
 
-    /**
-     * Adds an activity {@param r} at the given {@param index}. The activity {@param r} must either
-     * be in the current task or unparented to any task.
-     */
-    void addActivityAtIndex(int index, ActivityRecord r) {
-        TaskRecord task = r.getTaskRecord();
-        if (task != null && task != this) {
-            throw new IllegalArgumentException("Can not add r=" + " to task=" + this
-                    + " current parent=" + task);
-        }
-
-        r.setTask(this);
+    /** Called when a Task child is added from the Task.java side. */
+    // TODO(task-unify): Just override addChild to do what is needed when someone calls to add a
+    // child.
+    void onChildAdded(ActivityRecord r, int index) {
+        r.inHistory = true;
 
         // Remove r first, and if it wasn't already in the list and it's fullscreen, count it.
         if (!mActivities.remove(r) && r.occludesParent()) {
@@ -1298,34 +1283,34 @@
             mAtmService.notifyTaskPersisterLocked(this, false);
         }
 
-        if (r.getParent() != null) {
-            // Only attempt to move in WM if the child has a controller. It is possible we haven't
-            // created controller for the activity we are starting yet.
-            mTask.positionChildAt(r, index);
-        }
-
         // Make sure the list of display UID whitelists is updated
         // now that this record is in a new task.
         mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
     }
 
-    /**
-     * Removes the specified activity from this task.
-     * @param r The {@link ActivityRecord} to remove.
-     * @return true if this was the last activity in the task.
-     */
-    boolean removeActivity(ActivityRecord r) {
-        return removeActivity(r, false /* reparenting */);
-    }
-
-    boolean removeActivity(ActivityRecord r, boolean reparenting) {
-        if (r.getTaskRecord() != this) {
-            throw new IllegalArgumentException(
-                    "Activity=" + r + " does not belong to task=" + this);
+    // TODO(task-unify): Merge onChildAdded method below into this since task will be a single
+    //  object.
+    void addChild(ActivityRecord r) {
+        if (r.getParent() != null) {
+            // Shouldn't already have a parent since we are just adding to the task...
+            throw new IllegalStateException(
+                    "r=" + r + " parent=" + r.getParent() + " task=" + this);
         }
 
-        r.setTask(null /* task */, reparenting /* reparenting */);
+        ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this);
+        // This means the activity isn't attached to Task.java yet. Go ahead and do that.
+        // TODO(task-unify): Remove/call super once we unify task level.
+        if (mTask != null) {
+            mTask.addChild(r, Integer.MAX_VALUE /* add on top */);
+        } else {
+            onChildAdded(r, Integer.MAX_VALUE);
+        }
+    }
 
+    /** Called when a Task child is removed from the Task.java side. */
+    // TODO(task-unify): Just override removeChild to do what is needed when someone calls to remove
+    // a child.
+    void onChildRemoved(ActivityRecord r) {
         if (mActivities.remove(r) && r.occludesParent()) {
             // Was previously in list.
             numFullscreen--;
@@ -1341,11 +1326,27 @@
             mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
         }
 
-        if (!hasChild()) {
-            return !mReuseTask;
+        if (hasChild()) {
+            updateEffectiveIntent();
+
+            // The following block can be executed multiple times if there is more than one overlay.
+            // {@link ActivityStackSupervisor#removeTaskByIdLocked} handles this by reverse lookup
+            // of the task by id and exiting early if not found.
+            if (onlyHasTaskOverlayActivities(false /* excludingFinishing */)) {
+                // When destroying a task, tell the supervisor to remove it so that any activity it
+                // has can be cleaned up correctly. This is currently the only place where we remove
+                // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays
+                // state into removeTask(), we just clear the task here before the other residual
+                // work.
+                // TODO: If the callers to removeTask() changes such that we have multiple places
+                //       where we are destroying the task, move this back into removeTask()
+                mAtmService.mStackSupervisor.removeTaskByIdLocked(mTaskId, false /* killProcess */,
+                        !REMOVE_FROM_RECENTS, "onChildRemoved");
+            }
+        } else if (!mReuseTask) {
+            // Remove entire task if it doesn't have any activity left and it isn't marked for reuse
+            mStack.removeTask(this, "onChildRemoved", REMOVE_TASK_MODE_DESTROYING);
         }
-        updateEffectiveIntent();
-        return false;
     }
 
     /**
@@ -2065,7 +2066,10 @@
             } else {
                 // Apply the given non-decor and stable insets to calculate the corresponding bounds
                 // for screen size of configuration.
-                final int rotation = parentConfig.windowConfiguration.getRotation();
+                int rotation = inOutConfig.windowConfiguration.getRotation();
+                if (rotation == ROTATION_UNDEFINED) {
+                    rotation = parentConfig.windowConfiguration.getRotation();
+                }
                 if (rotation != ROTATION_UNDEFINED && compatInsets != null) {
                     mTmpNonDecorBounds.set(bounds);
                     mTmpStableBounds.set(bounds);
@@ -2379,14 +2383,14 @@
         if (intent != null) {
             StringBuilder sb = new StringBuilder(128);
             sb.append(prefix); sb.append("intent={");
-            intent.toShortString(sb, false, true, false, true);
+            intent.toShortString(sb, false, true, false, false);
             sb.append('}');
             pw.println(sb.toString());
         }
         if (affinityIntent != null) {
             StringBuilder sb = new StringBuilder(128);
             sb.append(prefix); sb.append("affinityIntent={");
-            affinityIntent.toShortString(sb, false, true, false, true);
+            affinityIntent.toShortString(sb, false, true, false, false);
             sb.append('}');
             pw.println(sb.toString());
         }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index fc9a110..56211e2 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -52,6 +52,8 @@
 import static com.android.server.wm.StackProto.MINIMIZE_AMOUNT;
 import static com.android.server.wm.StackProto.TASKS;
 import static com.android.server.wm.StackProto.WINDOW_CONTAINER;
+import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -69,6 +71,7 @@
 import android.util.proto.ProtoOutputStream;
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
+import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -934,7 +937,7 @@
 
     @Override
     void removeIfPossible() {
-        if (isSelfOrChildAnimating()) {
+        if (isAnimating(TRANSITION | CHILDREN)) {
             mDeferRemoval = true;
             return;
         }
@@ -950,8 +953,8 @@
     }
 
     @Override
-    void onParentChanged() {
-        super.onParentChanged();
+    void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
+        super.onParentChanged(newParent, oldParent);
 
         if (getParent() != null || mDisplayContent == null) {
             return;
@@ -1792,7 +1795,7 @@
 
     /** Returns true if a removal action is still being deferred. */
     boolean checkCompleteDeferredRemoval() {
-        if (isSelfOrChildAnimating()) {
+        if (isAnimating(TRANSITION | CHILDREN)) {
             return true;
         }
         if (mDeferRemoval) {
@@ -1866,4 +1869,22 @@
     AnimatingActivityRegistry getAnimatingActivityRegistry() {
         return mAnimatingActivityRegistry;
     }
+
+    @Override
+    void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
+            Rect outSurfaceInsets) {
+        final Task task = getTopChild();
+        if (task != null) {
+            task.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
+        } else {
+            super.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
+        }
+    }
+
+    @Override
+    RemoteAnimationTarget createRemoteAnimationTarget(
+            RemoteAnimationController.RemoteAnimationRecord record) {
+        final Task task = getTopChild();
+        return task != null ? task.createRemoteAnimationTarget(record) : null;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 1e13aef..3632284 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -24,6 +24,8 @@
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
 
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
@@ -118,7 +120,8 @@
         }
 
         mFindResults.resetTopWallpaper = true;
-        if (w.mActivityRecord != null && w.mActivityRecord.isHidden() && !w.mActivityRecord.isSelfAnimating()) {
+        if (w.mActivityRecord != null && w.mActivityRecord.isHidden()
+                && !w.mActivityRecord.isAnimating(TRANSITION)) {
 
             // If this window's app token is hidden and not animating, it is of no interest to us.
             if (DEBUG_WALLPAPER) Slog.v(TAG, "Skipping hidden and not animating token: " + w);
@@ -136,7 +139,7 @@
         }
 
         final boolean keyguardGoingAwayWithWallpaper = (w.mActivityRecord != null
-                && w.mActivityRecord.isSelfAnimating()
+                && w.mActivityRecord.isAnimating(TRANSITION)
                 && AppTransition.isKeyguardGoingAwayTransit(w.mActivityRecord.getTransit())
                 && (w.mActivityRecord.getTransitFlags()
                         & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0);
@@ -159,7 +162,8 @@
 
         final RecentsAnimationController recentsAnimationController =
                 mService.getRecentsAnimationController();
-        final boolean animationWallpaper = w.mActivityRecord != null && w.mActivityRecord.getAnimation() != null
+        final boolean animationWallpaper = w.mActivityRecord != null
+                && w.mActivityRecord.getAnimation() != null
                 && w.mActivityRecord.getAnimation().getShowWallpaper();
         final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0
                 || animationWallpaper;
@@ -173,7 +177,7 @@
                 && (mWallpaperTarget == w || w.isDrawFinishedLw())) {
             if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: " + w);
             mFindResults.setWallpaperTarget(w);
-            if (w == mWallpaperTarget && w.isAnimating()) {
+            if (w == mWallpaperTarget && w.isAnimating(TRANSITION | PARENTS)) {
                 // The current wallpaper target is animating, so we'll look behind it for
                 // another possible target and figure out what is going on later.
                 if (DEBUG_WALLPAPER) Slog.v(TAG,
@@ -224,19 +228,19 @@
         if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + ", obscured="
                 + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??")
                 + " animating=" + ((wallpaperTarget != null && wallpaperTarget.mActivityRecord != null)
-                ? wallpaperTarget.mActivityRecord.isSelfAnimating() : null)
+                ? wallpaperTarget.mActivityRecord.isAnimating(TRANSITION) : null)
                 + " prev=" + mPrevWallpaperTarget
                 + " recentsAnimationWallpaperVisible=" + isAnimatingWithRecentsComponent);
         return (wallpaperTarget != null
                 && (!wallpaperTarget.mObscured
                         || isAnimatingWithRecentsComponent
                         || (wallpaperTarget.mActivityRecord != null
-                                && wallpaperTarget.mActivityRecord.isSelfAnimating())))
+                        && wallpaperTarget.mActivityRecord.isAnimating(TRANSITION))))
                 || mPrevWallpaperTarget != null;
     }
 
     boolean isWallpaperTargetAnimating() {
-        return mWallpaperTarget != null && mWallpaperTarget.isAnimating()
+        return mWallpaperTarget != null && mWallpaperTarget.isAnimating(TRANSITION | PARENTS)
                 && (mWallpaperTarget.mActivityRecord == null
                         || !mWallpaperTarget.mActivityRecord.isWaitingForTransitionStart());
     }
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 3a1d6e0..f7525a9 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -17,6 +17,8 @@
 package com.android.server.wm;
 
 import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
+import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -192,7 +194,7 @@
                 mService.mWindowPlacerLocked.requestTraversal();
             }
 
-            final boolean rootAnimating = mService.mRoot.isSelfOrChildAnimating();
+            final boolean rootAnimating = mService.mRoot.isAnimating(TRANSITION | CHILDREN);
             if (rootAnimating && !mLastRootAnimating) {
 
                 // Usually app transitions but quite a load onto the system already (with all the
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 037edf1..7ce2b5e 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -24,8 +24,15 @@
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.SurfaceControl.Transaction;
 
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
+import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
+import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowContainerProto.CONFIGURATION_CONTAINER;
 import static com.android.server.wm.WindowContainerProto.ORIENTATION;
 import static com.android.server.wm.WindowContainerProto.SURFACE_ANIMATOR;
@@ -33,7 +40,9 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.logWithStack;
 import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
+import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
 
 import android.annotation.CallSuper;
 import android.annotation.IntDef;
@@ -45,17 +54,24 @@
 import android.graphics.Rect;
 import android.os.Debug;
 import android.os.IBinder;
+import android.os.Trace;
+import android.util.Pair;
 import android.util.Pools;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
+import android.view.DisplayInfo;
 import android.view.MagnificationSpec;
+import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Builder;
 import android.view.SurfaceSession;
+import android.view.WindowManager;
+import android.view.animation.Animation;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.protolog.common.ProtoLog;
 import com.android.server.wm.SurfaceAnimator.Animatable;
 
 import java.io.PrintWriter;
@@ -106,6 +122,10 @@
      */
     private WindowContainer<WindowContainer> mParent = null;
 
+    // Set to true when we are performing a reparenting operation so we only send one
+    // onParentChanged() notification.
+    private boolean mReparenting;
+
     // List of children for this window container. List is in z-order as the children appear on
     // screen with the top-most window container at the tail of the list.
     protected final WindowList<E> mChildren = new WindowList<E>();
@@ -151,6 +171,29 @@
 
     private final Configuration mTmpConfig = new Configuration();
 
+    /** Interface for {@link #isAnimating} to check which cases for the container is animating. */
+    public interface AnimationFlags {
+        /**
+         * A bit flag indicates that {@link #isAnimating} should also return {@code true}
+         * even though the container is not yet animating, but the window container or its
+         * relatives as specified by PARENTS or CHILDREN are part of an {@link AppTransition}
+         * that is pending so an animation starts soon.
+         */
+        int TRANSITION = 1;
+
+        /**
+         * A bit flag indicates that {@link #isAnimating} should also check if one of the
+         * ancestors of the container are animating in addition to the container itself.
+         */
+        int PARENTS = 2;
+
+        /**
+         * A bit flag indicates that {@link #isAnimating} should also check if one of the
+         * descendants of the container are animating in addition to the container itself.
+         */
+        int CHILDREN = 4;
+    }
+
     /**
      * Callback which is triggered while changing the parent, after setting up the surface but
      * before asking the parent to assign child layers.
@@ -159,6 +202,47 @@
         void onPreAssignChildLayers();
     }
 
+    /**
+     * True if this an AppWindowToken and the activity which created this was launched with
+     * ActivityOptions.setLaunchTaskBehind.
+     *
+     * TODO(b/142617871): We run a special animation when the activity was launched with that
+     * flag, but it's not necessary anymore. Keep the window invisible until the task is explicitly
+     * selected to suppress an animation, and remove this flag.
+     */
+    boolean mLaunchTaskBehind;
+
+    /**
+     * If we are running an animation, this determines the transition type. Must be one of
+     * {@link AppTransition#TransitionFlags}.
+     */
+    int mTransit;
+
+    /**
+     * If we are running an animation, this determines the flags during this animation. Must be a
+     * bitwise combination of AppTransition.TRANSIT_FLAG_* constants.
+     */
+    int mTransitFlags;
+
+    /** Whether this container should be boosted at the top of all its siblings. */
+    @VisibleForTesting boolean mNeedsZBoost;
+
+    /** Layer used to constrain the animation to a container's stack bounds. */
+    SurfaceControl mAnimationBoundsLayer;
+
+    /** Whether this container needs to create mAnimationBoundsLayer for cropping animations. */
+    boolean mNeedsAnimationBoundsLayer;
+
+    /**
+     * This gets used during some open/close transitions as well as during a change transition
+     * where it represents the starting-state snapshot.
+     */
+    AppWindowThumbnail mThumbnail;
+    final Rect mTransitStartRect = new Rect();
+    final Point mTmpPoint = new Point();
+    protected final Rect mTmpRect = new Rect();
+    final Rect mTmpPrevBounds = new Rect();
+
     WindowContainer(WindowManagerService wms) {
         mWmService = wms;
         mPendingTransaction = wms.mTransactionFactory.get();
@@ -187,9 +271,45 @@
         scheduleAnimation();
     }
 
+    void reparent(WindowContainer newParent, int position) {
+        if (newParent == null) {
+            throw new IllegalArgumentException("reparent: can't reparent to null " + this);
+        }
+
+        final WindowContainer oldParent = mParent;
+        if (mParent == newParent) {
+            throw new IllegalArgumentException("WC=" + this + " already child of " + mParent);
+        }
+
+        // The display object before reparenting as that might lead to old parent getting removed
+        // from the display if it no longer has any child.
+        final DisplayContent prevDc = oldParent.getDisplayContent();
+        final DisplayContent dc = newParent.getDisplayContent();
+
+        mReparenting = true;
+        oldParent.removeChild(this);
+        newParent.addChild(this, position);
+        mReparenting = false;
+
+        // Send onParentChanged notification here is we disabled sending it in setParent for
+        // reparenting case.
+        onParentChanged(newParent, oldParent);
+
+        // Relayout display(s)
+        dc.setLayoutNeeded();
+        if (prevDc != dc) {
+            onDisplayChanged(dc);
+            prevDc.setLayoutNeeded();
+        }
+        getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+    }
+
     final protected void setParent(WindowContainer<WindowContainer> parent) {
+        final WindowContainer oldParent = mParent;
         mParent = parent;
-        onParentChanged();
+        if (!mReparenting) {
+            onParentChanged(mParent, oldParent);
+        }
     }
 
     /**
@@ -197,12 +317,13 @@
      * Supposed to be overridden and contain actions that should be executed after parent was set.
      */
     @Override
-    void onParentChanged() {
-        onParentChanged(null);
+    void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
+        onParentChanged(newParent, oldParent, null);
     }
 
-    void onParentChanged(PreAssignChildLayersCallback callback) {
-        super.onParentChanged();
+    void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent,
+            PreAssignChildLayersCallback callback) {
+        super.onParentChanged(newParent, oldParent);
         if (mParent == null) {
             return;
         }
@@ -601,51 +722,78 @@
     }
 
     /**
-     * @return Whether our own container is running an animation or any child, no matter how deep in
-     *         the hierarchy, is animating.
+     * @return {@code true} when this container or its related containers are running an
+     * animation, {@code false} otherwise.
+     *
+     * By default this predicate only checks if this container itself is actually running an
+     * animation, but you can extend the check target over its relatives, or relax the condition
+     * so that this can return {@code true} if an animation starts soon by giving a combination
+     * of {@link #AnimationFlags}.
+     *
+     * Note that you can give a combination of bitmask flags to specify targets and condition for
+     * checking animating status.
+     * e.g. {@code isAnimating(TRANSITION | PARENT)} returns {@code true} if either this
+     * container itself or one of its parents is running an animation or waiting for an app
+     * transition.
+     *
+     * Note that TRANSITION propagates to parents and children as well.
+     *
+     * {@see AnimationFlags#TRANSITION}
+     * {@see AnimationFlags#PARENTS}
+     * {@see AnimationFlags#CHILDREN}
      */
-    boolean isSelfOrChildAnimating() {
-        if (isSelfAnimating()) {
+    final boolean isAnimating(int flags) {
+        if (mSurfaceAnimator.isAnimating()) {
             return true;
         }
-        for (int j = mChildren.size() - 1; j >= 0; j--) {
-            final WindowContainer wc = mChildren.get(j);
-            if (wc.isSelfOrChildAnimating()) {
+        if ((flags & TRANSITION) != 0 && isWaitingForTransitionStart()) {
+            return true;
+        }
+        if ((flags & PARENTS) != 0) {
+            final WindowContainer parent = getParent();
+            if (parent != null && parent.isAnimating(flags & ~CHILDREN)) {
                 return true;
             }
         }
+        if ((flags & CHILDREN) != 0) {
+            for (int i = 0; i < mChildren.size(); ++i) {
+                final WindowContainer wc = mChildren.get(i);
+                if (wc.isAnimating(flags & ~PARENTS)) {
+                    return true;
+                }
+            }
+        }
         return false;
     }
 
     /**
-     * @return Whether our own container is running an animation or our parent is animating. This
-     *         doesn't consider whether children are animating.
+     * @return {@code true} when the container is waiting the app transition start, {@code false}
+     *         otherwise.
      */
-    boolean isAnimating() {
-
-        // We are animating if we ourselves are animating or if our parent is animating.
-        return isSelfAnimating() || mParent != null && mParent.isAnimating();
+    boolean isWaitingForTransitionStart() {
+        return false;
     }
 
     /**
-     * @return {@code true} if in this subtree of the hierarchy we have an {@link AppWindowToken}
-     *         that is {@link #isSelfAnimating}; {@code false} otherwise.
+     * @return {@code true} if in this subtree of the hierarchy we have an
+     *         {@ode ActivityRecord#isAnimating(TRANSITION)}, {@code false} otherwise.
      */
-    boolean isAppAnimating() {
-        for (int j = mChildren.size() - 1; j >= 0; j--) {
-            final WindowContainer wc = mChildren.get(j);
-            if (wc.isAppAnimating()) {
-                return true;
-            }
-        }
-        return false;
+    boolean isAppTransitioning() {
+        return forAllActivities(app -> app.isAnimating(TRANSITION));
     }
 
     /**
      * @return Whether our own container running an animation at the moment.
      */
-    boolean isSelfAnimating() {
-        return mSurfaceAnimator.isAnimating();
+    final boolean isAnimating() {
+        return isAnimating(0 /* self only */);
+    }
+
+    /**
+     * @return {@code true} if the container is in changing app transition.
+     */
+    boolean isChangingAppTransition() {
+        return false;
     }
 
     void sendAppVisibilityToClients() {
@@ -947,10 +1095,13 @@
         wrapper.release();
     }
 
-    void forAllActivities(Consumer<ActivityRecord> callback) {
+    boolean forAllActivities(ToBooleanFunction<ActivityRecord> callback) {
         for (int i = mChildren.size() - 1; i >= 0; --i) {
-            mChildren.get(i).forAllActivities(callback);
+            if (mChildren.get(i).forAllActivities(callback)) {
+                return true;
+            }
         }
+        return false;
     }
 
     void forAllWallpaperWindows(Consumer<WallpaperWindowToken> callback) {
@@ -1333,6 +1484,203 @@
         return null;
     }
 
+    // TODO: Remove this and use #getBounds() instead once we set an app transition animation
+    // on TaskStack.
+    Rect getAnimationBounds(int appStackClipMode) {
+        return getBounds();
+    }
+
+    /**
+     * Applies the app transition animation according the given the layout properties in the
+     * window hierarchy.
+     *
+     * @param lp The layout parameters of the window.
+     * @param transit The app transition type indicates what kind of transition to be applied.
+     * @param enter Whether the app transition is entering transition or not.
+     * @param isVoiceInteraction Whether the container is participating in voice interaction or not.
+     *
+     * @return {@code true} when the container applied the app transition, {@code false} if the
+     *         app transition is disabled or skipped.
+     *
+     * @see #getAnimationAdapter
+     */
+    boolean applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
+                           boolean isVoiceInteraction) {
+        if (mWmService.mDisableTransitionAnimation) {
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
+                    "applyAnimation: transition animation is disabled or skipped. "
+                            + "container=%s", this);
+            cancelAnimation();
+            return false;
+        }
+
+        // Only apply an animation if the display isn't frozen. If it is frozen, there is no reason
+        // to animate and it can cause strange artifacts when we unfreeze the display if some
+        // different animation is running.
+        try {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WC#applyAnimation");
+            if (okToAnimate()) {
+                Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp, transit,
+                        enter, isVoiceInteraction);
+                AnimationAdapter adapter = adapters.first;
+                AnimationAdapter thumbnailAdapter = adapters.second;
+                if (adapter != null) {
+                    startAnimation(getPendingTransaction(), adapter, !isVisible());
+                    if (adapter.getShowWallpaper()) {
+                        mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+                    }
+                    if (thumbnailAdapter != null) {
+                        mThumbnail.startAnimation(
+                                getPendingTransaction(), thumbnailAdapter, !isVisible());
+                    }
+                }
+            } else {
+                cancelAnimation();
+            }
+        } finally {
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+        }
+
+        return isAnimating();
+    }
+
+    /**
+     * Gets the {@link AnimationAdapter} according the given window layout properties in the window
+     * hierarchy.
+     *
+     * @return The return value will always contain two elements, one for normal animations and the
+     *         other for thumbnail animation, both can be {@code null}.
+     *
+     * @See com.android.server.wm.RemoteAnimationController.RemoteAnimationRecord
+     * @See LocalAnimationAdapter
+     */
+    Pair<AnimationAdapter, AnimationAdapter> getAnimationAdapter(WindowManager.LayoutParams lp,
+            int transit, boolean enter, boolean isVoiceInteraction) {
+        final Pair<AnimationAdapter, AnimationAdapter> resultAdapters;
+        final int appStackClipMode = getDisplayContent().mAppTransition.getAppStackClipMode();
+
+        // Separate position and size for use in animators.
+        mTmpRect.set(getAnimationBounds(appStackClipMode));
+        mTmpPoint.set(mTmpRect.left, mTmpRect.top);
+        mTmpRect.offsetTo(0, 0);
+
+        final RemoteAnimationController controller =
+                getDisplayContent().mAppTransition.getRemoteAnimationController();
+        final boolean isChanging = AppTransition.isChangeTransit(transit) && enter
+                && isChangingAppTransition();
+
+        // Delaying animation start isn't compatible with remote animations at all.
+        if (controller != null && !mSurfaceAnimator.isAnimationStartDelayed()) {
+            final RemoteAnimationController.RemoteAnimationRecord adapters =
+                    controller.createRemoteAnimationRecord(this, mTmpPoint, mTmpRect,
+                            (isChanging ? mTransitStartRect : null));
+            resultAdapters = new Pair<>(adapters.mAdapter, adapters.mThumbnailAdapter);
+        } else if (isChanging) {
+            final float durationScale = mWmService.getTransitionAnimationScaleLocked();
+            final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo();
+            mTmpRect.offsetTo(mTmpPoint.x, mTmpPoint.y);
+
+            AnimationAdapter adapter = new LocalAnimationAdapter(
+                    new WindowChangeAnimationSpec(mTransitStartRect, mTmpRect, displayInfo,
+                            durationScale, true /* isAppAnimation */, false /* isThumbnail */),
+                    getSurfaceAnimationRunner());
+
+            AnimationAdapter thumbnailAdapter = null;
+            if (mThumbnail != null) {
+                thumbnailAdapter = new LocalAnimationAdapter(
+                        new WindowChangeAnimationSpec(mTransitStartRect, mTmpRect, displayInfo,
+                                durationScale, true /* isAppAnimation */, true /* isThumbnail */),
+                        getSurfaceAnimationRunner());
+            }
+            resultAdapters = new Pair<>(adapter, thumbnailAdapter);
+            mTransit = transit;
+            mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
+        } else {
+            mNeedsAnimationBoundsLayer = (appStackClipMode == STACK_CLIP_AFTER_ANIM);
+            final Animation a = loadAnimation(lp, transit, enter, isVoiceInteraction);
+
+            if (a != null) {
+                // Only apply corner radius to animation if we're not in multi window mode.
+                // We don't want rounded corners when in pip or split screen.
+                final float windowCornerRadius = !inMultiWindowMode()
+                        ? getDisplayContent().getWindowCornerRadius()
+                        : 0;
+                AnimationAdapter adapter = new LocalAnimationAdapter(
+                        new WindowAnimationSpec(a, mTmpPoint, mTmpRect,
+                                getDisplayContent().mAppTransition.canSkipFirstFrame(),
+                                appStackClipMode, true /* isAppAnimation */, windowCornerRadius),
+                        getSurfaceAnimationRunner());
+
+                resultAdapters = new Pair<>(adapter, null);
+                mNeedsZBoost = a.getZAdjustment() == Animation.ZORDER_TOP;
+                mTransit = transit;
+                mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
+            } else {
+                resultAdapters = new Pair<>(null, null);
+            }
+        }
+        return resultAdapters;
+    }
+
+    final SurfaceAnimationRunner getSurfaceAnimationRunner() {
+        return mWmService.mSurfaceAnimationRunner;
+    }
+
+    private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
+                                    boolean isVoiceInteraction) {
+        final DisplayContent displayContent = getDisplayContent();
+        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+        final int width = displayInfo.appWidth;
+        final int height = displayInfo.appHeight;
+        ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, "applyAnimation: container=%s", this);
+
+        // Determine the visible rect to calculate the thumbnail clip with
+        // getAnimationFrames.
+        final Rect frame = new Rect(0, 0, width, height);
+        final Rect displayFrame = new Rect(0, 0,
+                displayInfo.logicalWidth, displayInfo.logicalHeight);
+        final Rect insets = new Rect();
+        final Rect stableInsets = new Rect();
+        final Rect surfaceInsets = new Rect();
+        getAnimationFrames(frame, insets, stableInsets, surfaceInsets);
+
+        if (mLaunchTaskBehind) {
+            // Differentiate the two animations. This one which is briefly on the screen
+            // gets the !enter animation, and the other one which remains on the
+            // screen gets the enter animation. Both appear in the mOpeningApps set.
+            enter = false;
+        }
+        ProtoLog.d(WM_DEBUG_APP_TRANSITIONS,
+                "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s "
+                        + "surfaceInsets=%s",
+                AppTransition.appTransitionToString(transit), enter, frame, insets, surfaceInsets);
+        final Configuration displayConfig = displayContent.getConfiguration();
+        final Animation a = getDisplayContent().mAppTransition.loadAnimation(lp, transit, enter,
+                displayConfig.uiMode, displayConfig.orientation, frame, displayFrame, insets,
+                surfaceInsets, stableInsets, isVoiceInteraction, inFreeformWindowingMode(), this);
+        if (a != null) {
+            if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + this);
+            final int containingWidth = frame.width();
+            final int containingHeight = frame.height();
+            a.initialize(containingWidth, containingHeight, width, height);
+            a.scaleCurrentDuration(mWmService.getTransitionAnimationScaleLocked());
+        }
+        return a;
+    }
+
+    RemoteAnimationTarget createRemoteAnimationTarget(
+            RemoteAnimationController.RemoteAnimationRecord record) {
+        return null;
+    }
+
+    boolean okToDisplay() {
+        return mDisplayContent != null && mDisplayContent.okToDisplay();
+    }
+
+    boolean okToAnimate() {
+        return mDisplayContent != null && mDisplayContent.okToAnimate();
+    }
+
     @Override
     public void commitPendingTransaction() {
         scheduleAnimation();
@@ -1432,6 +1780,26 @@
         return getBounds();
     }
 
+    /**
+     * The {@code outFrame} retrieved by this method specifies where the animation will finish
+     * the entrance animation, as the next frame will display the window at these coordinates. In
+     * case of exit animation, this is where the animation will start, as the frame before the
+     * animation is displaying the window at these bounds.
+     *
+     * @param outFrame The bounds where entrance animation finishes or exit animation starts.
+     * @param outInsets Insets that are covered by system windows.
+     * @param outStableInsets Insets that determine the area covered by the stable system windows.
+     * @param outSurfaceInsets Positive insets between the drawing surface and window content.
+     */
+    void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
+            Rect outSurfaceInsets) {
+        final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo();
+        outFrame.set(0, 0, displayInfo.appWidth, displayInfo.appHeight);
+        outInsets.setEmpty();
+        outStableInsets.setEmpty();
+        outSurfaceInsets.setEmpty();
+    }
+
     void getRelativeDisplayedPosition(Point outPos) {
         final Rect dispBounds = getDisplayedBounds();
         outPos.set(dispBounds.left, dispBounds.top);
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 0cb4826..d224972 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -216,7 +216,7 @@
      *
      * @param displayId The logical display id.
      * @param callbacks The callbacks to invoke.
-     * @return {@code false} if display id is not valid.
+     * @return {@code false} if display id is not valid or an embedded display.
      */
     public abstract boolean setMagnificationCallbacks(int displayId,
             @Nullable MagnificationCallbacks callbacks);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 63ce1b1..ab937e0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -39,6 +39,7 @@
 import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP;
 import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS;
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
+import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
 import static android.view.Display.DEFAULT_DISPLAY;
@@ -93,6 +94,9 @@
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT;
 import static com.android.server.wm.ProtoLogGroup.WM_ERROR;
 import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
+import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
+import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
@@ -717,6 +721,8 @@
                 Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT);
         private final Uri mForceResizableUri = Settings.Global.getUriFor(
                 DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES);
+        private final Uri mSizeCompatFreeformUri = Settings.Global.getUriFor(
+                DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM);
 
         public SettingsObserver() {
             super(new Handler());
@@ -737,6 +743,8 @@
                     UserHandle.USER_ALL);
             resolver.registerContentObserver(mFreeformWindowUri, false, this, UserHandle.USER_ALL);
             resolver.registerContentObserver(mForceResizableUri, false, this, UserHandle.USER_ALL);
+            resolver.registerContentObserver(mSizeCompatFreeformUri, false, this,
+                    UserHandle.USER_ALL);
         }
 
         @Override
@@ -775,6 +783,11 @@
                 return;
             }
 
+            if (mSizeCompatFreeformUri.equals(uri)) {
+                updateSizeCompatFreeform();
+                return;
+            }
+
             @UpdateAnimationScaleMode
             final int mode;
             if (mWindowAnimationScaleUri.equals(uri)) {
@@ -844,6 +857,14 @@
 
             mAtmService.mForceResizableActivities = forceResizable;
         }
+
+        void updateSizeCompatFreeform() {
+            ContentResolver resolver = mContext.getContentResolver();
+            final boolean sizeCompatFreeform = Settings.Global.getInt(resolver,
+                    DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM, 0) != 0;
+
+            mAtmService.mSizeCompatFreeform = sizeCompatFreeform;
+        }
     }
 
     PowerManager mPowerManager;
@@ -2400,7 +2421,7 @@
         if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
             focusMayChange = true;
             win.mAnimatingExit = true;
-        } else if (win.isAnimating()) {
+        } else if (win.isAnimating(TRANSITION | PARENTS)) {
             // Currently in a hide animation... turn this into
             // an exit.
             win.mAnimatingExit = true;
@@ -7331,6 +7352,9 @@
             synchronized (mGlobalLock) {
                 final DisplayContent dc = mRoot.getDisplayContent(displayId);
                 if (dc != null && dc.mInputMethodTarget != null) {
+                    // If there was a pending IME show(), reset it as IME has been
+                    // requested to be hidden.
+                    dc.getInsetsStateController().getImeSourceProvider().abortShowImePostLayout();
                     dc.mInputMethodTarget.hideInsets(WindowInsets.Type.ime(), true /* fromIme */);
                 }
             }
@@ -7597,7 +7621,7 @@
     private void waitForAnimationsToComplete() {
         synchronized (mGlobalLock) {
             long timeoutRemaining = ANIMATION_COMPLETED_TIMEOUT_MS;
-            while (mRoot.isSelfOrChildAnimating() && timeoutRemaining > 0) {
+            while (mRoot.isAnimating(TRANSITION | CHILDREN) && timeoutRemaining > 0) {
                 long startTime = System.currentTimeMillis();
                 try {
                     mGlobalLock.wait(timeoutRemaining);
@@ -7606,7 +7630,7 @@
                 timeoutRemaining -= (System.currentTimeMillis() - startTime);
             }
 
-            if (mRoot.isSelfOrChildAnimating()) {
+            if (mRoot.isAnimating(TRANSITION | CHILDREN)) {
                 Log.w(TAG, "Timed out waiting for animations to complete.");
             }
         }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b9cf29a..1d11acd 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -98,6 +98,8 @@
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RESIZE;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
@@ -868,8 +870,8 @@
     }
 
     @Override
-    void onParentChanged() {
-        super.onParentChanged();
+    void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
+        super.onParentChanged(newParent, oldParent);
         setDrawnStateEvaluated(false /*evaluated*/);
 
         getDisplayContent().reapplyMagnificationSpec();
@@ -1492,7 +1494,8 @@
     @Override
     boolean hasContentToDisplay() {
         if (!mAppFreezing && isDrawnLw() && (mViewVisibility == View.VISIBLE
-                || (isAnimating() && !getDisplayContent().mAppTransition.isTransitionSet()))) {
+                || (isAnimating(TRANSITION | PARENTS)
+                && !getDisplayContent().mAppTransition.isTransitionSet()))) {
             return true;
         }
 
@@ -1550,8 +1553,8 @@
      */
     // TODO: Can we consolidate this with #isVisible() or have a more appropriate name for this?
     boolean isWinVisibleLw() {
-        return (mActivityRecord == null || !mActivityRecord.hiddenRequested || mActivityRecord.isSelfAnimating())
-                && isVisible();
+        return (mActivityRecord == null || !mActivityRecord.hiddenRequested
+                || mActivityRecord.isAnimating(TRANSITION)) && isVisible();
     }
 
     /**
@@ -1597,9 +1600,9 @@
         final ActivityRecord atoken = mActivityRecord;
         if (atoken != null) {
             return ((!isParentWindowHidden() && !atoken.hiddenRequested)
-                    || isAnimating());
+                    || isAnimating(TRANSITION | PARENTS));
         }
-        return !isParentWindowHidden() || isAnimating();
+        return !isParentWindowHidden() || isAnimating(TRANSITION | PARENTS);
     }
 
     /**
@@ -1634,7 +1637,7 @@
         final boolean parentAndClientVisible = !isParentWindowHidden()
                 && mViewVisibility == View.VISIBLE && !mToken.isHidden();
         return mHasSurface && isVisibleByPolicy() && !mDestroying
-                && (parentAndClientVisible || isAnimating());
+                && (parentAndClientVisible || isAnimating(TRANSITION | PARENTS));
     }
 
     // TODO: Another visibility method that was added late in the release to minimize risk.
@@ -1664,7 +1667,7 @@
         final ActivityRecord atoken = mActivityRecord;
         return isDrawnLw() && isVisibleByPolicy()
                 && ((!isParentWindowHidden() && (atoken == null || !atoken.hiddenRequested))
-                        || isAnimating());
+                        || isAnimating(TRANSITION | PARENTS));
     }
 
     /**
@@ -1672,7 +1675,7 @@
      */
     @Override
     public boolean isAnimatingLw() {
-        return isAnimating();
+        return isAnimating(TRANSITION | PARENTS);
     }
 
     @Override
@@ -1718,7 +1721,7 @@
         // to determine if it's occluding apps.
         return ((!mIsWallpaper && mAttrs.format == PixelFormat.OPAQUE)
                 || (mIsWallpaper && mWallpaperVisible))
-                && isDrawnLw() && !isAnimating();
+                && isDrawnLw() && !isAnimating(TRANSITION | PARENTS);
     }
 
     @Override
@@ -1740,7 +1743,7 @@
             // Starting window that's exiting will be removed when the animation finishes.
             // Mark all relevant flags for that onExitAnimationDone will proceed all the way
             // to actually remove it.
-            if (!visible && isVisibleNow() && mActivityRecord.isSelfAnimating()) {
+            if (!visible && isVisibleNow() && mActivityRecord.isAnimating(TRANSITION)) {
                 mAnimatingExit = true;
                 mRemoveOnExit = true;
                 mWindowRemovalAllowed = true;
@@ -2013,12 +2016,12 @@
             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
                     "Remove %s: mSurfaceController=%s mAnimatingExit=%b mRemoveOnExit=%b "
                             + "mHasSurface=%b surfaceShowing=%b animating=%b app-animation=%b "
-                            + "mWillReplaceWindow=%b inPendingTransaction=%b mDisplayFrozen=%b "
-                            + "callers=%s",
+                            + "mWillReplaceWindow=%b mDisplayFrozen=%b callers=%s",
                     this, mWinAnimator.mSurfaceController, mAnimatingExit, mRemoveOnExit,
-                    mHasSurface, mWinAnimator.getShown(), isAnimating(),
-                    mActivityRecord != null && mActivityRecord.isSelfAnimating(), mWillReplaceWindow,
-                    mActivityRecord != null && mActivityRecord.inPendingTransaction,
+                    mHasSurface, mWinAnimator.getShown(),
+                    isAnimating(TRANSITION | PARENTS),
+                    mActivityRecord != null && mActivityRecord.isAnimating(TRANSITION),
+                    mWillReplaceWindow,
                     mWmService.mDisplayFrozen, Debug.getCallers(6));
 
             // Visibility of the removed window. Will be used later to update orientation later on.
@@ -2076,7 +2079,7 @@
                         mWmService.mAccessibilityController.onWindowTransitionLocked(this, transit);
                     }
                 }
-                final boolean isAnimating = isAnimating()
+                final boolean isAnimating = isAnimating(TRANSITION | PARENTS)
                         && (mActivityRecord == null || !mActivityRecord.isWaitingForTransitionStart());
                 final boolean lastWindowIsStartingWindow = startingWindow && mActivityRecord != null
                         && mActivityRecord.isLastWindow(this);
@@ -2204,7 +2207,6 @@
         mInputChannel = inputChannels[0];
         mClientChannel = inputChannels[1];
         mWmService.mInputManager.registerInputChannel(mInputChannel);
-        mClientChannel.setToken(mInputChannel.getToken());
         mInputWindowHandle.token = mInputChannel.getToken();
         if (outInputChannel != null) {
             mClientChannel.transferTo(outInputChannel);
@@ -2319,29 +2321,6 @@
         final Region region = inputWindowHandle.touchableRegion;
         setTouchableRegionCropIfNeeded(inputWindowHandle);
 
-        final Rect appOverrideBounds = mActivityRecord != null
-                ? mActivityRecord.getResolvedOverrideBounds() : null;
-        if (appOverrideBounds != null && !appOverrideBounds.isEmpty()) {
-            // There may have touchable letterboxes around the activity, so in order to let the
-            // letterboxes are able to receive touch event and slip to activity, the activity with
-            // compatibility bounds cannot occupy full screen touchable region.
-            if (modal) {
-                // A modal window uses the whole compatibility bounds.
-                flags |= FLAG_NOT_TOUCH_MODAL;
-                mTmpRect.set(0, 0, appOverrideBounds.width(), appOverrideBounds.height());
-            } else {
-                // Non-modal uses the application based frame.
-                mTmpRect.set(mWindowFrames.mCompatFrame);
-            }
-            // The offset of compatibility bounds is applied to surface of {@link #ActivityRecord}
-            // and frame, so it is unnecessary to translate twice in surface based coordinates.
-            final int surfaceOffsetX = mActivityRecord.hasSizeCompatBounds()
-                    ? mActivityRecord.getBounds().left : 0;
-            mTmpRect.offset(surfaceOffsetX - mWindowFrames.mFrame.left, -mWindowFrames.mFrame.top);
-            region.set(mTmpRect);
-            return flags;
-        }
-
         if (modal && mActivityRecord != null) {
             // Limit the outer touch to the activity stack region.
             flags |= FLAG_NOT_TOUCH_MODAL;
@@ -2398,6 +2377,15 @@
         // Translate to surface based coordinates.
         region.translate(-mWindowFrames.mFrame.left, -mWindowFrames.mFrame.top);
 
+        // TODO(b/139804591): sizecompat layout needs to be reworked. Currently mFrame is post-
+        // scaling but the existing logic doesn't expect that. The result is that the already-
+        // scaled region ends up getting sent to surfaceflinger which then applies the scale
+        // (again). Until this is resolved, apply an inverse-scale here.
+        if (mActivityRecord != null && mActivityRecord.hasSizeCompatBounds()
+                && mGlobalScale != 1.f) {
+            region.scale(mInvGlobalScale);
+        }
+
         return flags;
     }
 
@@ -2697,10 +2685,11 @@
         if (DEBUG_VISIBILITY) Slog.v(TAG, "Policy visibility true: " + this);
         if (doAnimation) {
             if (DEBUG_VISIBILITY) Slog.v(TAG, "doAnimation: mPolicyVisibility="
-                    + isLegacyPolicyVisibility() + " animating=" + isAnimating());
+                    + isLegacyPolicyVisibility()
+                    + " animating=" + isAnimating(TRANSITION | PARENTS));
             if (!mToken.okToAnimate()) {
                 doAnimation = false;
-            } else if (isLegacyPolicyVisibility() && !isAnimating()) {
+            } else if (isLegacyPolicyVisibility() && !isAnimating(TRANSITION | PARENTS)) {
                 // Check for the case where we are currently visible and
                 // not animating; we do not want to do animation at such a
                 // point to become visible when we already are.
@@ -2740,7 +2729,7 @@
         }
         if (doAnimation) {
             mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
-            if (!isAnimating()) {
+            if (!isAnimating(TRANSITION | PARENTS)) {
                 doAnimation = false;
             }
         }
@@ -4177,9 +4166,9 @@
                     + " tok.hiddenRequested="
                     + (mActivityRecord != null && mActivityRecord.hiddenRequested)
                     + " tok.hidden=" + (mActivityRecord != null && mActivityRecord.isHidden())
-                    + " animating=" + isAnimating()
+                    + " animating=" + isAnimating(TRANSITION | PARENTS)
                     + " tok animating="
-                    + (mActivityRecord != null && mActivityRecord.isSelfAnimating())
+                    + (mActivityRecord != null && mActivityRecord.isAnimating(TRANSITION))
                     + " Callers=" + Debug.getCallers(4));
         }
     }
@@ -4406,7 +4395,7 @@
     void onExitAnimationDone() {
         if (DEBUG_ANIM) Slog.v(TAG, "onExitAnimationDone in " + this
                 + ": exiting=" + mAnimatingExit + " remove=" + mRemoveOnExit
-                + " selfAnimating=" + isSelfAnimating());
+                + " selfAnimating=" + isAnimating());
 
         if (!mChildren.isEmpty()) {
             // Copying to a different list as multiple children can be removed.
@@ -4429,7 +4418,7 @@
             }
         }
 
-        if (isSelfAnimating()) {
+        if (isAnimating()) {
             return;
         }
         if (mWmService.mAccessibilityController != null) {
@@ -4577,25 +4566,25 @@
         }
         if (DEBUG_VISIBILITY) {
             Slog.v(TAG, "Win " + this + ": isDrawn=" + isDrawnLw()
-                    + ", animating=" + isAnimating());
+                    + ", animating=" + isAnimating(TRANSITION | PARENTS));
             if (!isDrawnLw()) {
                 Slog.v(TAG, "Not displayed: s=" + mWinAnimator.mSurfaceController
                         + " pv=" + isVisibleByPolicy()
                         + " mDrawState=" + mWinAnimator.mDrawState
                         + " ph=" + isParentWindowHidden()
                         + " th=" + (mActivityRecord != null ? mActivityRecord.hiddenRequested : false)
-                        + " a=" + isAnimating());
+                        + " a=" + isAnimating(TRANSITION | PARENTS));
             }
         }
 
         results.numInteresting++;
         if (isDrawnLw()) {
             results.numDrawn++;
-            if (!isAnimating()) {
+            if (!isAnimating(TRANSITION | PARENTS)) {
                 results.numVisible++;
             }
             results.nowGone = false;
-        } else if (isAnimating()) {
+        } else if (isAnimating(TRANSITION | PARENTS)) {
             results.nowGone = false;
         }
     }
@@ -4732,7 +4721,7 @@
                     + mRemoveOnExit + ", mDestroying=" + mDestroying);
 
             // Cancel the existing exit animation for the next enter animation.
-            if (isSelfAnimating()) {
+            if (isAnimating()) {
                 cancelAnimation();
                 destroySurfaceUnchecked();
             }
@@ -5412,4 +5401,29 @@
         }
         return mKeyInterceptionInfo;
     }
+
+    @Override
+    void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
+            Rect outSurfaceInsets) {
+        // Containing frame will usually cover the whole screen, including dialog windows.
+        // For freeform workspace windows it will not cover the whole screen and it also
+        // won't exactly match the final freeform window frame (e.g. when overlapping with
+        // the status bar). In that case we need to use the final frame.
+        if (inFreeformWindowingMode()) {
+            outFrame.set(getFrameLw());
+        } else if (isLetterboxedAppWindow()) {
+            outFrame.set(getTask().getBounds());
+        } else if (isDockedResizing()) {
+            // If we are animating while docked resizing, then use the stack bounds as the
+            // animation target (which will be different than the task bounds)
+            outFrame.set(getTask().getParent().getBounds());
+        } else {
+            outFrame.set(getContainingFrame());
+        }
+        outSurfaceInsets.set(getAttrs().surfaceInsets);
+        // TODO(b/72757033): These are insets relative to the window frame, but we're really
+        // interested in the insets relative to the frame we chose in the if-blocks above.
+        getContentInsets(outInsets);
+        getStableInsets(outStableInsets);
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 3f25f89..fef3a9d 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -32,6 +32,8 @@
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
 import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
 import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
+import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
@@ -435,7 +437,7 @@
             return;
         }
 
-        if (!mWin.mActivityRecord.isSelfAnimating()) {
+        if (!mWin.mActivityRecord.isAnimating(TRANSITION)) {
             mWin.mActivityRecord.clearAllDrawn();
         } else {
             // Currently animating, persist current state of allDrawn until animation
@@ -1169,7 +1171,7 @@
                 w.mToken.hasVisible = true;
             }
         } else {
-            if (DEBUG_ANIM && mWin.isAnimating()) {
+            if (DEBUG_ANIM && mWin.isAnimating(TRANSITION | PARENTS)) {
                 Slog.v(TAG, "prepareSurface: No changes in animation for " + this);
             }
             displayed = true;
@@ -1332,7 +1334,7 @@
      * @return true if an animation has been loaded.
      */
     boolean applyAnimationLocked(int transit, boolean isEntrance) {
-        if (mWin.isSelfAnimating() && mAnimationIsEntrance == isEntrance) {
+        if (mWin.isAnimating() && mAnimationIsEntrance == isEntrance) {
             // If we are trying to apply an animation, but already running
             // an animation of the same type, then just leave that one alone.
             return true;
@@ -1400,7 +1402,7 @@
             mWin.getDisplayContent().adjustForImeIfNeeded();
         }
 
-        return mWin.isAnimating();
+        return mWin.isAnimating(TRANSITION | PARENTS);
     }
 
     void writeToProto(ProtoOutputStream proto, long fieldId) {
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index ad71237..88a1458 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -22,6 +22,9 @@
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT;
+import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
+import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
@@ -159,13 +162,10 @@
 
         final int count = mChildren.size();
         boolean changed = false;
-        boolean delayed = false;
+        final boolean delayed = isAnimating(TRANSITION | PARENTS | CHILDREN);
 
         for (int i = 0; i < count; i++) {
             final WindowState win = mChildren.get(i);
-            if (win.isAnimating()) {
-                delayed = true;
-            }
             changed |= win.onSetAppExiting();
         }
 
@@ -321,14 +321,6 @@
         return toString();
     }
 
-    boolean okToDisplay() {
-        return mDisplayContent != null && mDisplayContent.okToDisplay();
-    }
-
-    boolean okToAnimate() {
-        return mDisplayContent != null && mDisplayContent.okToAnimate();
-    }
-
     /**
      * Return whether windows from this token can layer above the
      * system bars, or in other words extend outside of the "Decor Frame"
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index bcd1713..425b4b6 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -23,7 +23,6 @@
         "com_android_server_AlarmManagerService.cpp",
         "com_android_server_am_BatteryStatsService.cpp",
         "com_android_server_connectivity_Vpn.cpp",
-        "com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp",
         "com_android_server_ConsumerIrService.cpp",
         "com_android_server_devicepolicy_CryptoTestHelper.cpp",
         "com_android_server_HardwarePropertiesManagerService.cpp",
@@ -54,6 +53,7 @@
         "com_android_server_am_LowMemDetector.cpp",
         "onload.cpp",
         ":lib_networkStatsFactory_native",
+        ":tethering-jni-srcs",
     ],
 
     include_dirs: [
@@ -147,6 +147,7 @@
         "android.frameworks.sensorservice@1.0",
         "android.system.suspend@1.0",
         "suspend_control_aidl_interface-cpp",
+        "vintf-vibrator-cpp",
     ],
 
     static_libs: [
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index a8c7682..8ddb86b 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -17,6 +17,9 @@
 #define LOG_TAG "VibratorService"
 
 #include <android/hardware/vibrator/1.4/IVibrator.h>
+#include <android/hardware/vibrator/BnVibratorCallback.h>
+#include <android/hardware/vibrator/IVibrator.h>
+#include <binder/IServiceManager.h>
 
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
@@ -41,11 +44,147 @@
 namespace V1_2 = android::hardware::vibrator::V1_2;
 namespace V1_3 = android::hardware::vibrator::V1_3;
 namespace V1_4 = android::hardware::vibrator::V1_4;
+namespace aidl = android::hardware::vibrator;
 
 namespace android {
 
 static jmethodID sMethodIdOnComplete;
 
+// TODO(b/141828236): remove HIDL 1.4 and re-write all of this code to remove
+// shim
+class VibratorShim : public V1_4::IVibrator {
+  public:
+    VibratorShim(const sp<aidl::IVibrator>& vib) : mVib(vib) {}
+
+    Return<V1_0::Status> on(uint32_t timeoutMs) override {
+        return on_1_4(timeoutMs, nullptr);
+    }
+
+    Return<V1_0::Status> off() override {
+        return toHidlStatus(mVib->off());
+    }
+
+    Return<bool> supportsAmplitudeControl() override {
+        int32_t cap = 0;
+        if (!mVib->getCapabilities(&cap).isOk()) return false;
+        return (cap & aidl::IVibrator::CAP_AMPLITUDE_CONTROL) > 0;
+    }
+
+    Return<V1_0::Status> setAmplitude(uint8_t amplitude) override {
+        return toHidlStatus(mVib->setAmplitude(amplitude));
+    }
+
+    Return<void> perform(V1_0::Effect effect, V1_0::EffectStrength strength,
+                         perform_cb _hidl_cb) override {
+        return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb);
+    }
+
+    Return<void> perform_1_1(V1_1::Effect_1_1 effect, V1_0::EffectStrength strength,
+                             perform_1_1_cb _hidl_cb) override {
+        return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb);
+    }
+
+    Return<void> perform_1_2(V1_2::Effect effect, V1_0::EffectStrength strength,
+                             perform_1_2_cb _hidl_cb) override {
+        return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb);
+    }
+
+    Return<bool> supportsExternalControl() override {
+        int32_t cap = 0;
+        if (!mVib->getCapabilities(&cap).isOk()) return false;
+        return (cap & aidl::IVibrator::CAP_EXTERNAL_CONTROL) > 0;
+    }
+
+    Return<V1_0::Status> setExternalControl(bool enabled) override {
+        return toHidlStatus(mVib->setExternalControl(enabled));
+    }
+
+    Return<void> perform_1_3(V1_3::Effect effect, V1_0::EffectStrength strength,
+                             perform_1_3_cb _hidl_cb) override {
+        return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb);
+    }
+
+    Return<uint32_t> getCapabilities() override {
+        static_assert(static_cast<int32_t>(V1_4::Capabilities::ON_COMPLETION_CALLBACK) ==
+                      static_cast<int32_t>(aidl::IVibrator::CAP_ON_CALLBACK));
+        static_assert(static_cast<int32_t>(V1_4::Capabilities::PERFORM_COMPLETION_CALLBACK) ==
+                      static_cast<int32_t>(aidl::IVibrator::CAP_PERFORM_CALLBACK));
+
+        int32_t cap;
+        if (!mVib->getCapabilities(&cap).isOk()) return 0;
+        return (cap & (aidl::IVibrator::CAP_ON_CALLBACK |
+                       aidl::IVibrator::CAP_PERFORM_CALLBACK)) > 0;
+    }
+
+    Return<V1_0::Status> on_1_4(uint32_t timeoutMs,
+                                const sp<V1_4::IVibratorCallback>& callback) override {
+        sp<aidl::IVibratorCallback> cb = callback ? new CallbackShim(callback) : nullptr;
+        return toHidlStatus(mVib->on(timeoutMs, cb));
+    }
+
+    Return<void> perform_1_4(V1_3::Effect effect, V1_0::EffectStrength strength,
+                             const sp<V1_4::IVibratorCallback>& callback,
+                             perform_1_4_cb _hidl_cb) override {
+        static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) ==
+                      static_cast<uint8_t>(aidl::EffectStrength::LIGHT));
+        static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) ==
+                      static_cast<uint8_t>(aidl::EffectStrength::MEDIUM));
+        static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) ==
+                      static_cast<uint8_t>(aidl::EffectStrength::STRONG));
+        static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) ==
+                      static_cast<uint8_t>(aidl::Effect::CLICK));
+        static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) ==
+                      static_cast<uint8_t>(aidl::Effect::DOUBLE_CLICK));
+        static_assert(static_cast<uint8_t>(V1_3::Effect::TICK) ==
+                      static_cast<uint8_t>(aidl::Effect::TICK));
+        static_assert(static_cast<uint8_t>(V1_3::Effect::THUD) ==
+                      static_cast<uint8_t>(aidl::Effect::THUD));
+        static_assert(static_cast<uint8_t>(V1_3::Effect::POP) ==
+                      static_cast<uint8_t>(aidl::Effect::POP));
+        static_assert(static_cast<uint8_t>(V1_3::Effect::HEAVY_CLICK) ==
+                      static_cast<uint8_t>(aidl::Effect::HEAVY_CLICK));
+        static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_1) ==
+                      static_cast<uint8_t>(aidl::Effect::RINGTONE_1));
+        static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_2) ==
+                      static_cast<uint8_t>(aidl::Effect::RINGTONE_2));
+        static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) ==
+                      static_cast<uint8_t>(aidl::Effect::RINGTONE_15));
+        static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
+                      static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK));
+
+        sp<aidl::IVibratorCallback> cb = callback ? new CallbackShim(callback) : nullptr;
+        int timeoutMs = 0;
+        V1_0::Status status = toHidlStatus(
+            mVib->perform(static_cast<aidl::Effect>(effect),
+                          static_cast<aidl::EffectStrength>(strength), cb, &timeoutMs));
+        _hidl_cb(status, timeoutMs);
+        return android::hardware::Status::ok();
+    }
+  private:
+    sp<aidl::IVibrator> mVib;
+
+    V1_0::Status toHidlStatus(const android::binder::Status& status) {
+        switch(status.exceptionCode()) {
+            using android::hardware::Status;
+            case Status::EX_NONE: return V1_0::Status::OK;
+            case Status::EX_ILLEGAL_ARGUMENT: return V1_0::Status::BAD_VALUE;
+            case Status::EX_UNSUPPORTED_OPERATION: return V1_0::Status::UNSUPPORTED_OPERATION;
+        }
+        return V1_0::Status::UNKNOWN_ERROR;
+    }
+
+    class CallbackShim : public aidl::BnVibratorCallback {
+      public:
+        CallbackShim(const sp<V1_4::IVibratorCallback>& cb) : mCb(cb) {}
+        binder::Status onComplete() {
+            mCb->onComplete();
+            return binder::Status::ok(); // oneway, local call
+        }
+      private:
+        sp<V1_4::IVibratorCallback> mCb;
+    };
+};
+
 class VibratorCallback : public V1_4::IVibratorCallback {
     public:
         VibratorCallback(JNIEnv *env, jobject vibration) :
@@ -79,6 +218,11 @@
 class HalWrapper {
   public:
     static std::unique_ptr<HalWrapper> Create() {
+        sp<aidl::IVibrator> aidlVib = waitForVintfService<aidl::IVibrator>();
+        if (aidlVib) {
+            return std::unique_ptr<HalWrapper>(new HalWrapper(new VibratorShim(aidlVib)));
+        }
+
         // Assume that if getService returns a nullptr, HAL is not available on the
         // device.
         auto hal = I::getService();
@@ -190,7 +334,7 @@
     }
 }
 
-static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jint strength,
+static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jlong strength,
                                    jobject vibration) {
     Status status;
     uint32_t lengthMs;
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index dd2629d..b546a1d 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -709,6 +709,18 @@
     checkAndClearExceptionFromCallback(env, "notifyConfigurationChanged");
 }
 
+static jobject getInputApplicationHandleObjLocalRef(JNIEnv* env,
+        const sp<InputApplicationHandle>& inputApplicationHandle) {
+    if (inputApplicationHandle == nullptr) {
+        return nullptr;
+    }
+    NativeInputApplicationHandle* handle =
+            static_cast<NativeInputApplicationHandle*>(inputApplicationHandle.get());
+
+    return handle->getInputApplicationHandleObjLocalRef(env);
+}
+
+
 nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
         const sp<IBinder>& token, const std::string& reason) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
@@ -719,12 +731,15 @@
     JNIEnv* env = jniEnv();
     ScopedLocalFrame localFrame(env);
 
+    jobject inputApplicationHandleObj =
+            getInputApplicationHandleObjLocalRef(env, inputApplicationHandle);
+
     jobject tokenObj = javaObjectForIBinder(env, token);
     jstring reasonObj = env->NewStringUTF(reason.c_str());
 
     jlong newTimeout = env->CallLongMethod(mServiceObj,
-                gServiceClassInfo.notifyANR, tokenObj,
-                reasonObj);
+            gServiceClassInfo.notifyANR, inputApplicationHandleObj, tokenObj,
+                 reasonObj);
     if (checkAndClearExceptionFromCallback(env, "notifyANR")) {
         newTimeout = 0; // abort dispatch
     } else {
@@ -1581,8 +1596,8 @@
         return JNI_FALSE;
     }
 
-    if (im->getInputManager()->getDispatcher()->
-            transferTouchFocus(fromChannel->getToken(), toChannel->getToken())) {
+    if (im->getInputManager()->getDispatcher()->transferTouchFocus(
+            fromChannel->getConnectionToken(), toChannel->getConnectionToken())) {
         return JNI_TRUE;
     } else {
         return JNI_FALSE;
@@ -1865,7 +1880,7 @@
 
     GET_METHOD_ID(gServiceClassInfo.notifyANR, clazz,
             "notifyANR",
-            "(Landroid/os/IBinder;Ljava/lang/String;)J");
+            "(Landroid/view/InputApplicationHandle;Landroid/os/IBinder;Ljava/lang/String;)J");
 
     GET_METHOD_ID(gServiceClassInfo.filterInputEvent, clazz,
             "filterInputEvent", "(Landroid/view/InputEvent;I)Z");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 59996cc..5a1d552 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -62,4 +62,6 @@
             String packageName, boolean hasGrant) {
         return false;
     }
+
+    public void setLocationEnabled(ComponentName who, boolean locationEnabled) {}
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java
index 4a456f7..aa38880 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java
@@ -17,7 +17,6 @@
 package com.android.server.devicepolicy;
 
 import android.app.Notification;
-import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -26,12 +25,9 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
-import android.graphics.Color;
-import android.os.Build;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.os.storage.StorageManager;
 import android.provider.Settings;
 import android.security.Credentials;
@@ -39,9 +35,9 @@
 import android.security.KeyChain.KeyChainConnection;
 import android.util.Log;
 
+import com.android.internal.R;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
-import com.android.internal.R;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
@@ -49,7 +45,6 @@
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.util.List;
-import java.util.Set;
 
 public class CertificateMonitor {
     protected static final String LOG_TAG = DevicePolicyManagerService.LOG_TAG;
@@ -111,13 +106,13 @@
         }
     }
 
-    public List<String> getInstalledCaCertificates(UserHandle userHandle)
+    private List<String> getInstalledCaCertificates(UserHandle userHandle)
             throws RemoteException, RuntimeException {
         try (KeyChainConnection conn = mInjector.keyChainBindAsUser(userHandle)) {
             return conn.getService().getUserCaAliases().getList();
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
-            return null;
+            throw new RuntimeException(e);
         } catch (AssertionError e) {
             throw new RuntimeException(e);
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 453d05d..a39cc20 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4183,7 +4183,7 @@
     private boolean passwordQualityInvocationOrderCheckEnabled(String packageName, int userId) {
         try {
             return mIPlatformCompat.isChangeEnabledByPackageName(ADMIN_APP_PASSWORD_COMPLEXITY,
-                    packageName);
+                    packageName, userId);
         } catch (RemoteException e) {
             Log.e(LOG_TAG, "Failed to get a response from PLATFORM_COMPAT_SERVICE", e);
         }
@@ -8105,15 +8105,7 @@
         mSecurityLogMonitor.stop();
         setNetworkLoggingActiveInternal(false);
         deleteTransferOwnershipBundleLocked(userId);
-
-        try {
-            if (mInjector.getIBackupManager() != null) {
-                // Reactivate backup service.
-                mInjector.getIBackupManager().setBackupServiceActive(UserHandle.USER_SYSTEM, true);
-            }
-        } catch (RemoteException e) {
-            throw new IllegalStateException("Failed reactivating backup service.", e);
-        }
+        toggleBackupServiceActive(UserHandle.USER_SYSTEM, true);
     }
 
     @Override
@@ -8173,7 +8165,6 @@
         }
     }
 
-
     private void toggleBackupServiceActive(int userId, boolean makeActive) {
         long ident = mInjector.binderClearCallingIdentity();
         try {
@@ -8182,7 +8173,8 @@
                         .setBackupServiceActive(userId, makeActive);
             }
         } catch (RemoteException e) {
-            throw new IllegalStateException("Failed deactivating backup service.", e);
+            throw new IllegalStateException(String.format("Failed %s backup service.",
+                    makeActive ? "activating" : "deactivating"), e);
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
         }
@@ -8233,6 +8225,7 @@
         mOwners.removeProfileOwner(userId);
         mOwners.writeProfileOwner(userId);
         deleteTransferOwnershipBundleLocked(userId);
+        toggleBackupServiceActive(userId, true);
     }
 
     @Override
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5883048..2009dbd 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -27,6 +27,7 @@
 import android.annotation.NonNull;
 import android.annotation.StringRes;
 import android.app.ActivityThread;
+import android.app.AppCompatCallbacks;
 import android.app.INotificationManager;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.ComponentName;
@@ -646,6 +647,7 @@
         ServiceManager.addService(Context.PLATFORM_COMPAT_SERVICE, platformCompat);
         ServiceManager.addService(Context.PLATFORM_COMPAT_NATIVE_SERVICE,
                 new PlatformCompatNative(platformCompat));
+        AppCompatCallbacks.install(new long[0]);
         t.traceEnd();
 
         // Wait for installd to finish starting up so that it has a chance to
@@ -1133,7 +1135,6 @@
 
         StatusBarManagerService statusBar = null;
         INotificationManager notification = null;
-        LocationManagerService location = null;
         CountryDetectorService countryDetector = null;
         ILockSettings lockSettings = null;
         MediaRouterService mediaRouter = null;
@@ -1430,12 +1431,7 @@
             t.traceEnd();
 
             t.traceBegin("StartLocationManagerService");
-            try {
-                location = new LocationManagerService(context);
-                ServiceManager.addService(Context.LOCATION_SERVICE, location);
-            } catch (Throwable e) {
-                reportWtf("starting Location Manager", e);
-            }
+            mSystemServiceManager.startService(LocationManagerService.Lifecycle.class);
             t.traceEnd();
 
             t.traceBegin("StartCountryDetectorService");
@@ -2019,7 +2015,6 @@
         final NetworkStatsService networkStatsF = networkStats;
         final NetworkPolicyManagerService networkPolicyF = networkPolicy;
         final ConnectivityService connectivityF = connectivity;
-        final LocationManagerService locationF = location;
         final CountryDetectorService countryDetectorF = countryDetector;
         final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;
         final InputManagerService inputManagerF = inputManager;
@@ -2175,16 +2170,6 @@
             }
             t.traceEnd();
 
-
-            t.traceBegin("MakeLocationServiceReady");
-            try {
-                if (locationF != null) {
-                    locationF.systemRunning();
-                }
-            } catch (Throwable e) {
-                reportWtf("Notifying Location Service running", e);
-            }
-            t.traceEnd();
             t.traceBegin("MakeCountryDetectionServiceReady");
             try {
                 if (countryDetectorF != null) {
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 1ca96ed..c56ecd6 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -1,10 +1,14 @@
 java_library_static {
     name: "services.net",
-    srcs: ["java/**/*.java"],
+    srcs: [
+        ":tethering-servicesnet-srcs",
+        "java/**/*.java",
+    ],
     static_libs: [
         "dnsresolver_aidl_interface-V2-java",
-        "netd_aidl_interface-java",
+        "netd_aidl_interface-unstable-java",
         "networkstack-client",
+        "tethering-client",
     ],
 }
 
@@ -17,3 +21,18 @@
         "java/android/net/netlink/*.java",
     ],
 }
+
+filegroup {
+    name: "services-tethering-shared-srcs",
+    srcs: [
+        ":framework-annotations",
+        "java/android/net/ConnectivityModuleConnector.java",
+        "java/android/net/NetworkStackClient.java",
+        "java/android/net/ip/InterfaceController.java",
+        "java/android/net/netlink/*.java",
+        "java/android/net/util/InterfaceParams.java",
+        "java/android/net/util/NetdService.java",
+        "java/android/net/util/NetworkConstants.java",
+        "java/android/net/util/SharedLog.java"
+    ],
+}
diff --git a/services/net/java/android/net/netlink/InetDiagMessage.java b/services/net/java/android/net/netlink/InetDiagMessage.java
index 31a2556..ca07630 100644
--- a/services/net/java/android/net/netlink/InetDiagMessage.java
+++ b/services/net/java/android/net/netlink/InetDiagMessage.java
@@ -26,6 +26,7 @@
 import static android.system.OsConstants.IPPROTO_UDP;
 import static android.system.OsConstants.NETLINK_INET_DIAG;
 
+import android.annotation.Nullable;
 import android.net.util.SocketUtils;
 import android.system.ErrnoException;
 import android.util.Log;
@@ -53,7 +54,35 @@
     private static final int TIMEOUT_MS = 500;
 
     public static byte[] InetDiagReqV2(int protocol, InetSocketAddress local,
-                                       InetSocketAddress remote, int family, short flags) {
+            InetSocketAddress remote, int family, short flags) {
+        return InetDiagReqV2(protocol, local, remote, family, flags, 0 /* pad */,
+                0 /* idiagExt */, StructInetDiagReqV2.INET_DIAG_REQ_V2_ALL_STATES);
+    }
+
+    /**
+     * Construct an inet_diag_req_v2 message. This method will throw {@code NullPointerException}
+     * if local and remote are not both null or both non-null.
+     *
+     * @param protocol the request protocol type. This should be set to one of IPPROTO_TCP,
+     *                 IPPROTO_UDP, or IPPROTO_UDPLITE.
+     * @param local local socket address of the target socket. This will be packed into a
+     *              {@Code StructInetDiagSockId}. Request to diagnose for all sockets if both of
+     *              local or remote address is null.
+     * @param remote remote socket address of the target socket. This will be packed into a
+     *              {@Code StructInetDiagSockId}. Request to diagnose for all sockets if both of
+     *              local or remote address is null.
+     * @param family the ip family of the request message. This should be set to either AF_INET or
+     *               AF_INET6 for IPv4 or IPv6 sockets respectively.
+     * @param flags message flags. See &lt;linux_src&gt;/include/uapi/linux/netlink.h.
+     * @param pad for raw socket protocol specification.
+     * @param idiagExt a set of flags defining what kind of extended information to report.
+     * @param state a bit mask that defines a filter of socket states.
+     *
+     * @return bytes array representation of the message
+     **/
+    public static byte[] InetDiagReqV2(int protocol, @Nullable InetSocketAddress local,
+            @Nullable InetSocketAddress remote, int family, short flags, int pad, int idiagExt,
+            int state) throws NullPointerException {
         final byte[] bytes = new byte[StructNlMsgHdr.STRUCT_SIZE + StructInetDiagReqV2.STRUCT_SIZE];
         final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
         byteBuffer.order(ByteOrder.nativeOrder());
@@ -63,9 +92,9 @@
         nlMsgHdr.nlmsg_type = SOCK_DIAG_BY_FAMILY;
         nlMsgHdr.nlmsg_flags = flags;
         nlMsgHdr.pack(byteBuffer);
+        final StructInetDiagReqV2 inetDiagReqV2 =
+                new StructInetDiagReqV2(protocol, local, remote, family, pad, idiagExt, state);
 
-        final StructInetDiagReqV2 inetDiagReqV2 = new StructInetDiagReqV2(protocol, local, remote,
-                family);
         inetDiagReqV2.pack(byteBuffer);
         return bytes;
     }
diff --git a/services/net/java/android/net/netlink/StructInetDiagReqV2.java b/services/net/java/android/net/netlink/StructInetDiagReqV2.java
index 49a9325..2268113 100644
--- a/services/net/java/android/net/netlink/StructInetDiagReqV2.java
+++ b/services/net/java/android/net/netlink/StructInetDiagReqV2.java
@@ -16,10 +16,10 @@
 
 package android.net.netlink;
 
-import static java.nio.ByteOrder.BIG_ENDIAN;
+import android.annotation.Nullable;
+
 import java.net.InetSocketAddress;
 import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
 /**
  * struct inet_diag_req_v2
@@ -40,41 +40,58 @@
 public class StructInetDiagReqV2 {
     public static final int STRUCT_SIZE = 8 + StructInetDiagSockId.STRUCT_SIZE;
 
-    private final byte sdiag_family;
-    private final byte sdiag_protocol;
-    private final StructInetDiagSockId id;
-    private final int INET_DIAG_REQ_V2_ALL_STATES = (int) 0xffffffff;
-
+    private final byte mSdiagFamily;
+    private final byte mSdiagProtocol;
+    private final byte mIdiagExt;
+    private final byte mPad;
+    private final StructInetDiagSockId mId;
+    private final int mState;
+    public static final int INET_DIAG_REQ_V2_ALL_STATES = (int) 0xffffffff;
 
     public StructInetDiagReqV2(int protocol, InetSocketAddress local, InetSocketAddress remote,
-                               int family) {
-        sdiag_family = (byte) family;
-        sdiag_protocol = (byte) protocol;
-        id = new StructInetDiagSockId(local, remote);
+            int family) {
+        this(protocol, local, remote, family, 0 /* pad */, 0 /* extension */,
+                INET_DIAG_REQ_V2_ALL_STATES);
+    }
+
+    public StructInetDiagReqV2(int protocol, @Nullable InetSocketAddress local,
+            @Nullable InetSocketAddress remote, int family, int pad, int extension, int state)
+            throws NullPointerException {
+        mSdiagFamily = (byte) family;
+        mSdiagProtocol = (byte) protocol;
+        // Request for all sockets if no specific socket is requested. Specify the local and remote
+        // socket address information for target request socket.
+        if ((local == null) != (remote == null)) {
+            throw new NullPointerException("Local and remote must be both null or both non-null");
+        }
+        mId = ((local != null && remote != null) ? new StructInetDiagSockId(local, remote) : null);
+        mPad = (byte) pad;
+        mIdiagExt = (byte) extension;
+        mState = state;
     }
 
     public void pack(ByteBuffer byteBuffer) {
         // The ByteOrder must have already been set by the caller.
-        byteBuffer.put((byte) sdiag_family);
-        byteBuffer.put((byte) sdiag_protocol);
-        byteBuffer.put((byte) 0);
-        byteBuffer.put((byte) 0);
-        byteBuffer.putInt(INET_DIAG_REQ_V2_ALL_STATES);
-        id.pack(byteBuffer);
+        byteBuffer.put((byte) mSdiagFamily);
+        byteBuffer.put((byte) mSdiagProtocol);
+        byteBuffer.put((byte) mIdiagExt);
+        byteBuffer.put((byte) mPad);
+        byteBuffer.putInt(mState);
+        if (mId != null) mId.pack(byteBuffer);
     }
 
     @Override
     public String toString() {
-        final String familyStr = NetlinkConstants.stringForAddressFamily(sdiag_family);
-        final String protocolStr = NetlinkConstants.stringForAddressFamily(sdiag_protocol);
+        final String familyStr = NetlinkConstants.stringForAddressFamily(mSdiagFamily);
+        final String protocolStr = NetlinkConstants.stringForAddressFamily(mSdiagProtocol);
 
         return "StructInetDiagReqV2{ "
                 + "sdiag_family{" + familyStr + "}, "
                 + "sdiag_protocol{" + protocolStr + "}, "
-                + "idiag_ext{" + 0 + ")}, "
-                + "pad{" + 0 + "}, "
-                + "idiag_states{" + Integer.toHexString(INET_DIAG_REQ_V2_ALL_STATES) + "}, "
-                + id.toString()
+                + "idiag_ext{" + mIdiagExt + ")}, "
+                + "pad{" + mPad + "}, "
+                + "idiag_states{" + Integer.toHexString(mState) + "}, "
+                + ((mId != null) ? mId.toString() : "inet_diag_sockid=null")
                 + "}";
     }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index 7b7b8e6..485f436 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -38,7 +38,6 @@
 import static com.android.server.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_LONG_TIME;
 import static com.android.server.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_SHORT_TIME;
 import static com.android.server.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION;
-import static com.android.server.AlarmManagerService.Constants.KEY_APP_STANDBY_QUOTAS_ENABLED;
 import static com.android.server.AlarmManagerService.Constants.KEY_LISTENER_TIMEOUT;
 import static com.android.server.AlarmManagerService.Constants.KEY_MAX_INTERVAL;
 import static com.android.server.AlarmManagerService.Constants.KEY_MIN_FUTURITY;
@@ -85,6 +84,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.server.usage.AppStandbyInternal;
 
 import org.junit.After;
 import org.junit.Before;
@@ -108,7 +108,7 @@
 
     private long mAppStandbyWindow;
     private AlarmManagerService mService;
-    private UsageStatsManagerInternal.AppIdleStateChangeListener mAppStandbyListener;
+    private AppStandbyInternal.AppIdleStateChangeListener mAppStandbyListener;
     private AlarmManagerService.ChargingReceiver mChargingReceiver;
     @Mock
     private ContentResolver mMockResolver;
@@ -119,6 +119,8 @@
     @Mock
     private UsageStatsManagerInternal mUsageStatsManagerInternal;
     @Mock
+    private AppStandbyInternal mAppStandbyInternal;
+    @Mock
     private AppStateTracker mAppStateTracker;
     @Mock
     private AlarmManagerService.ClockReceiver mClockReceiver;
@@ -257,6 +259,8 @@
         doReturn(mAppStateTracker).when(() -> LocalServices.getService(AppStateTracker.class));
         doReturn(null)
                 .when(() -> LocalServices.getService(DeviceIdleInternal.class));
+        doReturn(mAppStandbyInternal).when(
+                () -> LocalServices.getService(AppStandbyInternal.class));
         doReturn(mUsageStatsManagerInternal).when(
                 () -> LocalServices.getService(UsageStatsManagerInternal.class));
         when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE),
@@ -289,9 +293,9 @@
         assertEquals(0, mService.mConstants.MIN_FUTURITY);
         assertEquals(0, mService.mConstants.MIN_INTERVAL);
         mAppStandbyWindow = mService.mConstants.APP_STANDBY_WINDOW;
-        ArgumentCaptor<UsageStatsManagerInternal.AppIdleStateChangeListener> captor =
-                ArgumentCaptor.forClass(UsageStatsManagerInternal.AppIdleStateChangeListener.class);
-        verify(mUsageStatsManagerInternal).addAppIdleStateChangeListener(captor.capture());
+        ArgumentCaptor<AppStandbyInternal.AppIdleStateChangeListener> captor =
+                ArgumentCaptor.forClass(AppStandbyInternal.AppIdleStateChangeListener.class);
+        verify(mAppStandbyInternal).addListener(captor.capture());
         mAppStandbyListener = captor.getValue();
 
         ArgumentCaptor<AlarmManagerService.ChargingReceiver> chargingReceiverCaptor =
@@ -300,6 +304,8 @@
                 argThat((filter) -> filter.hasAction(BatteryManager.ACTION_CHARGING)
                         && filter.hasAction(BatteryManager.ACTION_DISCHARGING)));
         mChargingReceiver = chargingReceiverCaptor.getValue();
+
+        setTestableQuotas();
     }
 
     private void setTestAlarm(int type, long triggerTime, PendingIntent operation) {
@@ -337,9 +343,10 @@
     }
 
     /**
+     * Lowers quotas to make testing feasible.
      * Careful while calling as this will replace any existing settings for the calling test.
      */
-    private void setQuotasEnabled(boolean enabled) {
+    private void setTestableQuotas() {
         final StringBuilder constantsBuilder = new StringBuilder();
         constantsBuilder.append(KEY_MIN_FUTURITY);
         constantsBuilder.append("=0,");
@@ -348,14 +355,9 @@
         constantsBuilder.append("=8,");
         constantsBuilder.append(mService.mConstants.KEYS_APP_STANDBY_QUOTAS[WORKING_INDEX]);
         constantsBuilder.append("=5,");
-        if (!enabled) {
-            constantsBuilder.append(KEY_APP_STANDBY_QUOTAS_ENABLED);
-            constantsBuilder.append("=false,");
-        }
         doReturn(constantsBuilder.toString()).when(() -> Settings.Global.getString(mMockResolver,
                 Settings.Global.ALARM_MANAGER_CONSTANTS));
         mService.mConstants.onChange(false, null);
-        assertEquals(mService.mConstants.APP_STANDBY_QUOTAS_ENABLED, enabled);
     }
 
     @Test
@@ -476,67 +478,6 @@
         assertEquals(mNowElapsedTest + 9, mTestTimer.getElapsed());
     }
 
-    @Test
-    public void testStandbyBucketDelay_workingSet() throws Exception {
-        setQuotasEnabled(false);
-        setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 5, getNewMockPendingIntent());
-        setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 6, getNewMockPendingIntent());
-        assertEquals(mNowElapsedTest + 5, mTestTimer.getElapsed());
-
-        when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
-                anyLong())).thenReturn(STANDBY_BUCKET_WORKING_SET);
-
-        mNowElapsedTest = mTestTimer.getElapsed();
-        mTestTimer.expire();
-
-        verify(mUsageStatsManagerInternal, atLeastOnce())
-                .getAppStandbyBucket(eq(TEST_CALLING_PACKAGE),
-                        eq(UserHandle.getUserId(TEST_CALLING_UID)), anyLong());
-        final long expectedNextTrigger = mNowElapsedTest
-                + mService.getMinDelayForBucketLocked(STANDBY_BUCKET_WORKING_SET);
-        assertEquals("Incorrect next alarm trigger", expectedNextTrigger, mTestTimer.getElapsed());
-    }
-
-    @Test
-    public void testStandbyBucketDelay_frequent() throws Exception {
-        setQuotasEnabled(false);
-        setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 5, getNewMockPendingIntent());
-        setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 6, getNewMockPendingIntent());
-        assertEquals(mNowElapsedTest + 5, mTestTimer.getElapsed());
-
-        when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
-                anyLong())).thenReturn(STANDBY_BUCKET_FREQUENT);
-        mNowElapsedTest = mTestTimer.getElapsed();
-        mTestTimer.expire();
-
-        verify(mUsageStatsManagerInternal, atLeastOnce())
-                .getAppStandbyBucket(eq(TEST_CALLING_PACKAGE),
-                        eq(UserHandle.getUserId(TEST_CALLING_UID)), anyLong());
-        final long expectedNextTrigger = mNowElapsedTest
-                + mService.getMinDelayForBucketLocked(STANDBY_BUCKET_FREQUENT);
-        assertEquals("Incorrect next alarm trigger.", expectedNextTrigger, mTestTimer.getElapsed());
-    }
-
-    @Test
-    public void testStandbyBucketDelay_rare() throws Exception {
-        setQuotasEnabled(false);
-        setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 5, getNewMockPendingIntent());
-        setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 6, getNewMockPendingIntent());
-        assertEquals(mNowElapsedTest + 5, mTestTimer.getElapsed());
-
-        when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
-                anyLong())).thenReturn(STANDBY_BUCKET_RARE);
-        mNowElapsedTest = mTestTimer.getElapsed();
-        mTestTimer.expire();
-
-        verify(mUsageStatsManagerInternal, atLeastOnce())
-                .getAppStandbyBucket(eq(TEST_CALLING_PACKAGE),
-                        eq(UserHandle.getUserId(TEST_CALLING_UID)), anyLong());
-        final long expectedNextTrigger = mNowElapsedTest
-                + mService.getMinDelayForBucketLocked(STANDBY_BUCKET_RARE);
-        assertEquals("Incorrect next alarm trigger.", expectedNextTrigger, mTestTimer.getElapsed());
-    }
-
     private void testQuotasDeferralOnSet(int standbyBucket) throws Exception {
         final int quota = mService.getQuotaForBucketLocked(standbyBucket);
         when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
@@ -596,73 +537,61 @@
 
     @Test
     public void testActiveQuota_deferredOnSet() throws Exception {
-        setQuotasEnabled(true);
         testQuotasDeferralOnSet(STANDBY_BUCKET_ACTIVE);
     }
 
     @Test
     public void testActiveQuota_deferredOnExpiration() throws Exception {
-        setQuotasEnabled(true);
         testQuotasDeferralOnExpiration(STANDBY_BUCKET_ACTIVE);
     }
 
     @Test
     public void testActiveQuota_notDeferred() throws Exception {
-        setQuotasEnabled(true);
         testQuotasNoDeferral(STANDBY_BUCKET_ACTIVE);
     }
 
     @Test
     public void testWorkingQuota_deferredOnSet() throws Exception {
-        setQuotasEnabled(true);
         testQuotasDeferralOnSet(STANDBY_BUCKET_WORKING_SET);
     }
 
     @Test
     public void testWorkingQuota_deferredOnExpiration() throws Exception {
-        setQuotasEnabled(true);
         testQuotasDeferralOnExpiration(STANDBY_BUCKET_WORKING_SET);
     }
 
     @Test
     public void testWorkingQuota_notDeferred() throws Exception {
-        setQuotasEnabled(true);
         testQuotasNoDeferral(STANDBY_BUCKET_WORKING_SET);
     }
 
     @Test
     public void testFrequentQuota_deferredOnSet() throws Exception {
-        setQuotasEnabled(true);
         testQuotasDeferralOnSet(STANDBY_BUCKET_FREQUENT);
     }
 
     @Test
     public void testFrequentQuota_deferredOnExpiration() throws Exception {
-        setQuotasEnabled(true);
         testQuotasDeferralOnExpiration(STANDBY_BUCKET_FREQUENT);
     }
 
     @Test
     public void testFrequentQuota_notDeferred() throws Exception {
-        setQuotasEnabled(true);
         testQuotasNoDeferral(STANDBY_BUCKET_FREQUENT);
     }
 
     @Test
     public void testRareQuota_deferredOnSet() throws Exception {
-        setQuotasEnabled(true);
         testQuotasDeferralOnSet(STANDBY_BUCKET_RARE);
     }
 
     @Test
     public void testRareQuota_deferredOnExpiration() throws Exception {
-        setQuotasEnabled(true);
         testQuotasDeferralOnExpiration(STANDBY_BUCKET_RARE);
     }
 
     @Test
     public void testRareQuota_notDeferred() throws Exception {
-        setQuotasEnabled(true);
         testQuotasNoDeferral(STANDBY_BUCKET_RARE);
     }
 
@@ -681,7 +610,6 @@
 
     @Test
     public void testQuotaDowngrade() throws Exception {
-        setQuotasEnabled(true);
         final int workingQuota = mService.getQuotaForBucketLocked(STANDBY_BUCKET_WORKING_SET);
         when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
                 anyLong())).thenReturn(STANDBY_BUCKET_WORKING_SET);
@@ -709,7 +637,6 @@
 
     @Test
     public void testQuotaUpgrade() throws Exception {
-        setQuotasEnabled(true);
         final int frequentQuota = mService.getQuotaForBucketLocked(STANDBY_BUCKET_FREQUENT);
         when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
                 anyLong())).thenReturn(STANDBY_BUCKET_FREQUENT);
@@ -747,7 +674,6 @@
 
     @Test
     public void testCharging() throws Exception {
-        setQuotasEnabled(true);
         final int workingQuota = mService.getQuotaForBucketLocked(STANDBY_BUCKET_WORKING_SET);
         when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
                 anyLong())).thenReturn(STANDBY_BUCKET_WORKING_SET);
diff --git a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
index 80d1129..1e27007 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
@@ -45,7 +45,6 @@
 import android.app.IUidObserver;
 import android.app.usage.UsageStatsManager;
 import android.app.usage.UsageStatsManagerInternal;
-import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -70,6 +69,8 @@
 import com.android.internal.app.IAppOpsCallback;
 import com.android.internal.app.IAppOpsService;
 import com.android.server.AppStateTracker.Listener;
+import com.android.server.usage.AppStandbyInternal;
+import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -128,8 +129,8 @@
         }
 
         @Override
-        UsageStatsManagerInternal injectUsageStatsManagerInternal() {
-            return mMockUsageStatsManagerInternal;
+        AppStandbyInternal injectAppStandbyInternal() {
+            return mMockAppStandbyInternal;
         }
 
         @Override
@@ -175,7 +176,7 @@
     private PowerManagerInternal mMockPowerManagerInternal;
 
     @Mock
-    private UsageStatsManagerInternal mMockUsageStatsManagerInternal;
+    private AppStandbyInternal mMockAppStandbyInternal;
 
     private MockContentResolver mMockContentResolver;
 
@@ -271,7 +272,7 @@
 
         verify(mMockContext).registerReceiver(
                 receiverCaptor.capture(), any(IntentFilter.class));
-        verify(mMockUsageStatsManagerInternal).addAppIdleStateChangeListener(
+        verify(mMockAppStandbyInternal).addListener(
                 appIdleStateChangeListenerCaptor.capture());
 
         mIUidObserver = uidObserverArgumentCaptor.getValue();
@@ -512,7 +513,8 @@
 
 
         mIUidObserver.onUidStateChanged(UID_2,
-                ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE, 0);
+                ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE, 0,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
 
         waitUntilMainHandlerDrain();
         assertTrue(instance.isUidActive(UID_1));
@@ -529,7 +531,8 @@
 
 
         mIUidObserver.onUidStateChanged(UID_1,
-                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
+                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
 
         waitUntilMainHandlerDrain();
         assertTrue(instance.isUidActive(UID_1));
@@ -563,7 +566,8 @@
         assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
 
         mIUidObserver.onUidStateChanged(UID_1,
-                ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0);
+                ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
 
         waitUntilMainHandlerDrain();
         assertFalse(instance.isUidActive(UID_1));
@@ -575,7 +579,8 @@
         assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
 
         mIUidObserver.onUidStateChanged(UID_1,
-                ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0);
+                ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
 
         waitUntilMainHandlerDrain();
         assertFalse(instance.isUidActive(UID_1));
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 6dd1bd8..e7f6a74 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -23,7 +23,6 @@
 import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
 import static android.app.ActivityManager.PROCESS_STATE_CACHED_RECENT;
 import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
-import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION;
 import static android.app.ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
 import static android.app.ActivityManager.PROCESS_STATE_HOME;
 import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
@@ -62,6 +61,7 @@
 import static com.android.server.am.ProcessList.VISIBLE_APP_ADJ;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.AdditionalAnswers.answer;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
@@ -368,7 +368,7 @@
         sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
         sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
 
-        assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION, PERCEPTIBLE_APP_ADJ,
+        assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
                 SCHED_GROUP_DEFAULT);
     }
 
@@ -543,6 +543,21 @@
 
     @SuppressWarnings("GuardedBy")
     @Test
+    public void testUpdateOomAdj_DoOne_NonCachedToCached() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+        app.cached = false;
+        app.setCurRawAdj(SERVICE_ADJ);
+        doReturn(null).when(sService).getTopAppLocked();
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+        assertTrue(ProcessList.CACHED_APP_MIN_ADJ <= app.setAdj);
+        assertTrue(ProcessList.CACHED_APP_MAX_ADJ >= app.setAdj);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
     public void testUpdateOomAdj_DoOne_Service_Started() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
index b6a7b09..fa209a7a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -16,7 +16,6 @@
 package com.android.server.appop;
 
 import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
-import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION;
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_ERRORED;
 import static android.app.AppOpsManager.MODE_FOREGROUND;
@@ -338,18 +337,22 @@
     public void testUidProcStateChange_cachedToTopToCached() throws Exception {
         setupProcStateTests();
 
-        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
                 .isNotEqualTo(MODE_ALLOWED);
 
-        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP);
+        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP,
+                ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
         assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
                 .isEqualTo(MODE_ALLOWED);
 
-        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         // Second time to make sure that settle time is overcome
         Thread.sleep(50);
-        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
                 .isNotEqualTo(MODE_ALLOWED);
     }
@@ -357,12 +360,13 @@
     @Test
     public void testUidProcStateChange_cachedToFgs() {
         setupProcStateTests();
-
-        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
                 .isNotEqualTo(MODE_ALLOWED);
 
-        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE);
+        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
                 .isNotEqualTo(MODE_ALLOWED);
     }
@@ -371,12 +375,13 @@
     public void testUidProcStateChange_cachedToFgsLocation() {
         setupProcStateTests();
 
-        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
                 .isNotEqualTo(MODE_ALLOWED);
 
-        mAppOpsService.updateUidProcState(mMyUid,
-                PROCESS_STATE_FOREGROUND_SERVICE_LOCATION);
+        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
+                ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
         assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
                 .isEqualTo(MODE_ALLOWED);
     }
@@ -385,18 +390,22 @@
     public void testUidProcStateChange_topToFgs() throws Exception {
         setupProcStateTests();
 
-        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
                 .isNotEqualTo(MODE_ALLOWED);
 
-        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP);
+        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP,
+                ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
         assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
                 .isEqualTo(MODE_ALLOWED);
 
-        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE);
+        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         // Second time to make sure that settle time is overcome
         Thread.sleep(50);
-        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE);
+        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
                 .isNotEqualTo(MODE_ALLOWED);
     }
@@ -405,25 +414,31 @@
     public void testUidProcStateChange_topToFgsLocationToFgs() throws Exception {
         setupProcStateTests();
 
-        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
                 .isNotEqualTo(MODE_ALLOWED);
 
-        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP);
+        mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP,
+                ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
         assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
                 .isEqualTo(MODE_ALLOWED);
 
-        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION);
+        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
+                ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
         // Second time to make sure that settle time is overcome
         Thread.sleep(50);
-        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION);
+        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
+                ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
         assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
                 .isEqualTo(MODE_ALLOWED);
 
-        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE);
+        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         // Second time to make sure that settle time is overcome
         Thread.sleep(50);
-        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE);
+        mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
                 .isNotEqualTo(MODE_ALLOWED);
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 8863d5a..5bd08c0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -233,7 +233,8 @@
             doReturn(procState).when(mActivityMangerInternal).getUidProcessState(uid);
             SparseBooleanArray foregroundUids = mQuotaController.getForegroundUids();
             spyOn(foregroundUids);
-            mUidObserver.onUidStateChanged(uid, procState, 0);
+            mUidObserver.onUidStateChanged(uid, procState, 0,
+                    ActivityManager.PROCESS_CAPABILITY_NONE);
             if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
                 verify(foregroundUids, timeout(2 * SECOND_IN_MILLIS).times(1))
                         .put(eq(uid), eq(true));
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 83e20fb..30ccb71 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -75,7 +75,7 @@
         "libui",
         "libunwindstack",
         "libutils",
-        "netd_aidl_interface-V2-cpp",
+        "netd_aidl_interface-cpp",
     ],
 
     dxflags: ["--multi-dex"],
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index 4d653b9..d34f783 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -23,6 +23,7 @@
         <option name="test-file-name" value="JobTestApp.apk" />
         <option name="test-file-name" value="ConnTestApp.apk" />
         <option name="test-file-name" value="SuspendTestApp.apk" />
+        <option name="test-file-name" value="SimpleServiceTestApp.apk" />
     </target_preparer>
 
     <option name="test-tag" value="FrameworksServicesTests" />
diff --git a/services/tests/servicestests/res/raw/apex_test.apex b/services/tests/servicestests/res/raw/apex_test.apex
new file mode 100644
index 0000000..19b1c5e
--- /dev/null
+++ b/services/tests/servicestests/res/raw/apex_test.apex
Binary files differ
diff --git a/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java b/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java
index 4a9dd97..0605d9e 100644
--- a/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java
@@ -36,7 +36,7 @@
     public void test1() {
         assertTrue("dynamic_system service available", mService != null);
         try {
-            mService.startInstallation(1 << 20, 8 << 30);
+            mService.startInstallation("userdata", 8L << 30, false);
             fail("DynamicSystemService did not throw SecurityException as expected");
         } catch (SecurityException e) {
             // expected
diff --git a/services/tests/servicestests/src/com/android/server/GnssManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/GnssManagerServiceTest.java
new file mode 100644
index 0000000..9692c25
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/GnssManagerServiceTest.java
@@ -0,0 +1,743 @@
+/*
+ * 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.server;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.Manifest;
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.location.GnssClock;
+import android.location.GnssMeasurementCorrections;
+import android.location.GnssMeasurementsEvent;
+import android.location.GnssNavigationMessage;
+import android.location.GnssSingleSatCorrection;
+import android.location.IBatchedLocationCallback;
+import android.location.IGnssMeasurementsListener;
+import android.location.IGnssNavigationMessageListener;
+import android.location.IGnssStatusListener;
+import android.location.INetInitiatedListener;
+import android.location.Location;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.Message;
+import android.os.RemoteException;
+
+import com.android.server.location.GnssBatchingProvider;
+import com.android.server.location.GnssCapabilitiesProvider;
+import com.android.server.location.GnssLocationProvider;
+import com.android.server.location.GnssMeasurementCorrectionsProvider;
+import com.android.server.location.GnssMeasurementsProvider;
+import com.android.server.location.GnssMeasurementsProvider.GnssMeasurementProviderNative;
+import com.android.server.location.GnssNavigationMessageProvider;
+import com.android.server.location.GnssNavigationMessageProvider.GnssNavigationMessageProviderNative;
+import com.android.server.location.GnssStatusListenerHelper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.AdditionalMatchers;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Unit tests for {@link com.android.server.GnssManagerService}.
+ */
+public class GnssManagerServiceTest {
+
+    // Gnss Providers
+    @Mock
+    private GnssLocationProvider mMockGnssLocationProvider;
+    @Mock
+    private GnssBatchingProvider mMockGnssBatchingProvider;
+    @Mock
+    private GnssLocationProvider.GnssSystemInfoProvider mMockGnssSystemInfoProvider;
+    @Mock
+    private GnssCapabilitiesProvider mMockGnssCapabilitiesProvider;
+    @Mock
+    private GnssMeasurementCorrectionsProvider mMockGnssMeasurementCorrectionsProvider;
+    @Mock
+    private INetInitiatedListener mMockNetInitiatedListener;
+    private GnssMeasurementsProvider mTestGnssMeasurementsProvider;
+    private GnssStatusListenerHelper mTestGnssStatusProvider;
+    private GnssNavigationMessageProvider mTestGnssNavigationMessageProvider;
+
+    // Managers and services
+    @Mock
+    private AppOpsManager mMockAppOpsManager;
+    @Mock
+    private ActivityManager mMockActivityManager;
+    @Mock
+    private LocationManagerService mMockLocationManagerService;
+
+    // Context and handler
+    @Mock
+    private Handler mMockHandler;
+    @Mock
+    private Context mMockContext;
+
+    // Class under test
+    private GnssManagerService mGnssManagerService;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        GnssLocationProvider.setIsSupportedForTest(true);
+
+        // Set up mock context
+        when(mMockContext.getSystemServiceName(AppOpsManager.class)).thenReturn(
+                Context.APP_OPS_SERVICE);
+        when(mMockContext.getSystemServiceName(ActivityManager.class)).thenReturn(
+                Context.ACTIVITY_SERVICE);
+        when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(
+                mMockAppOpsManager);
+        when(mMockContext.getSystemService(
+                eq(Context.ACTIVITY_SERVICE))).thenReturn(
+                mMockActivityManager);
+        enableLocationPermissions();
+
+        // Mock Handler will execute posted runnables immediately
+        when(mMockHandler.sendMessageAtTime(any(Message.class), anyLong())).thenAnswer(
+                (InvocationOnMock invocation) -> {
+                    Message msg = (Message) (invocation.getArguments()[0]);
+                    msg.getCallback().run();
+                    return null;
+                });
+
+        // Setup providers
+        mTestGnssMeasurementsProvider = createGnssMeasurementsProvider(
+                mMockContext, mMockHandler);
+        mTestGnssStatusProvider = createGnssStatusListenerHelper(
+                mMockContext, mMockHandler);
+        mTestGnssNavigationMessageProvider = createGnssNavigationMessageProvider(
+                mMockContext, mMockHandler);
+
+        // Setup GnssLocationProvider to return providers
+        when(mMockGnssLocationProvider.getGnssStatusProvider()).thenReturn(
+                mTestGnssStatusProvider);
+        when(mMockGnssLocationProvider.getGnssBatchingProvider()).thenReturn(
+                mMockGnssBatchingProvider);
+        when(mMockGnssLocationProvider.getGnssCapabilitiesProvider()).thenReturn(
+                mMockGnssCapabilitiesProvider);
+        when(mMockGnssLocationProvider.getGnssSystemInfoProvider()).thenReturn(
+                mMockGnssSystemInfoProvider);
+        when(mMockGnssLocationProvider.getGnssMeasurementCorrectionsProvider()).thenReturn(
+                mMockGnssMeasurementCorrectionsProvider);
+        when(mMockGnssLocationProvider.getGnssMeasurementsProvider()).thenReturn(
+                mTestGnssMeasurementsProvider);
+        when(mMockGnssLocationProvider.getGnssNavigationMessageProvider()).thenReturn(
+                mTestGnssNavigationMessageProvider);
+        when(mMockGnssLocationProvider.getNetInitiatedListener()).thenReturn(
+                mMockNetInitiatedListener);
+
+        // Setup GnssBatching provider
+        when(mMockGnssBatchingProvider.start(anyLong(), anyBoolean())).thenReturn(true);
+        when(mMockGnssBatchingProvider.stop()).thenReturn(true);
+
+        // Create GnssManagerService
+        mGnssManagerService = new GnssManagerService(mMockLocationManagerService, mMockContext,
+                mMockGnssLocationProvider, new LocationUsageLogger());
+    }
+
+    private void overrideAsBinder(IInterface mockListener) {
+        IBinder mockBinder = mock(IBinder.class);
+        when(mockListener.asBinder()).thenReturn(mockBinder);
+    }
+
+    private IGnssStatusListener createMockGnssStatusListener() {
+        IGnssStatusListener mockListener = mock(IGnssStatusListener.class);
+        overrideAsBinder(mockListener);
+        return mockListener;
+    }
+
+    private IGnssMeasurementsListener createMockGnssMeasurementsListener() {
+        IGnssMeasurementsListener mockListener = mock(
+                IGnssMeasurementsListener.class);
+        overrideAsBinder(mockListener);
+        return mockListener;
+    }
+
+    private IBatchedLocationCallback createMockBatchedLocationCallback() {
+        IBatchedLocationCallback mockedCallback = mock(IBatchedLocationCallback.class);
+        overrideAsBinder(mockedCallback);
+        return mockedCallback;
+    }
+
+    private IGnssNavigationMessageListener createMockGnssNavigationMessageListener() {
+        IGnssNavigationMessageListener mockListener = mock(IGnssNavigationMessageListener.class);
+        overrideAsBinder(mockListener);
+        return mockListener;
+    }
+
+    private GnssMeasurementCorrections createDummyGnssMeasurementCorrections() {
+        GnssSingleSatCorrection gnssSingleSatCorrection =
+                new GnssSingleSatCorrection.Builder().build();
+        return
+                new GnssMeasurementCorrections.Builder().setSingleSatelliteCorrectionList(
+                        Arrays.asList(gnssSingleSatCorrection)).build();
+    }
+
+    private void enableLocationPermissions() {
+        Mockito.doThrow(new SecurityException()).when(
+                mMockContext).enforceCallingPermission(
+                AdditionalMatchers.and(
+                        AdditionalMatchers.not(eq(Manifest.permission.LOCATION_HARDWARE)),
+                        AdditionalMatchers.not(eq(Manifest.permission.ACCESS_FINE_LOCATION))),
+                anyString());
+        when(mMockContext.checkPermission(
+                eq(android.Manifest.permission.LOCATION_HARDWARE), anyInt(), anyInt())).thenReturn(
+                PackageManager.PERMISSION_GRANTED);
+
+        // AppOpsManager will return true if OP_FINE_LOCATION is checked
+        when(mMockAppOpsManager.checkOp(anyInt(), anyInt(), anyString())).thenAnswer(
+                (InvocationOnMock invocation) -> {
+                    int code = (int) (invocation.getArguments()[0]);
+                    if (code == AppOpsManager.OP_FINE_LOCATION) {
+                        return AppOpsManager.MODE_ALLOWED;
+                    }
+                    return AppOpsManager.MODE_ERRORED;
+                });
+    }
+
+    private void disableLocationPermissions() {
+        Mockito.doThrow(new SecurityException()).when(
+                mMockContext).enforceCallingPermission(anyString(), anyString());
+        Mockito.doThrow(new SecurityException()).when(
+                mMockContext).checkPermission(anyString(), anyInt(), anyInt());
+
+        when(mMockAppOpsManager.checkOp(anyInt(), anyInt(),
+                anyString())).thenReturn(AppOpsManager.MODE_ERRORED);
+    }
+
+    private GnssStatusListenerHelper createGnssStatusListenerHelper(Context context,
+            Handler handler) {
+        return new GnssStatusListenerHelper(
+                context, handler) {
+            @Override
+            protected boolean isAvailableInPlatform() {
+                return true;
+            }
+
+            @Override
+            protected boolean isGpsEnabled() {
+                return true;
+            }
+        };
+    }
+
+    private GnssMeasurementsProvider createGnssMeasurementsProvider(Context context,
+            Handler handler) {
+        GnssMeasurementProviderNative
+                mockGnssMeasurementProviderNative = mock(GnssMeasurementProviderNative.class);
+        return new GnssMeasurementsProvider(
+                context, handler, mockGnssMeasurementProviderNative) {
+            @Override
+            protected boolean isGpsEnabled() {
+                return true;
+            }
+        };
+    }
+
+    private GnssNavigationMessageProvider createGnssNavigationMessageProvider(Context context,
+            Handler handler) {
+        GnssNavigationMessageProviderNative mockGnssNavigationMessageProviderNative = mock(
+                GnssNavigationMessageProviderNative.class);
+        return new GnssNavigationMessageProvider(context, handler,
+                mockGnssNavigationMessageProviderNative) {
+            @Override
+            protected boolean isGpsEnabled() {
+                return true;
+            }
+        };
+    }
+
+    @Test
+    public void getGnssYearOfHardwareTest() {
+        final int gnssYearOfHardware = 2012;
+        when(mMockGnssSystemInfoProvider.getGnssYearOfHardware()).thenReturn(gnssYearOfHardware);
+        enableLocationPermissions();
+
+        assertThat(mGnssManagerService.getGnssYearOfHardware()).isEqualTo(gnssYearOfHardware);
+    }
+
+    @Test
+    public void getGnssHardwareModelNameTest() {
+        final String gnssHardwareModelName = "hardwarename";
+        when(mMockGnssSystemInfoProvider.getGnssHardwareModelName()).thenReturn(
+                gnssHardwareModelName);
+        enableLocationPermissions();
+
+        assertThat(mGnssManagerService.getGnssHardwareModelName()).isEqualTo(
+                gnssHardwareModelName);
+    }
+
+    @Test
+    public void getGnssCapabilitiesWithoutPermissionsTest() {
+        disableLocationPermissions();
+
+        assertThrows(SecurityException.class,
+                () -> mGnssManagerService.getGnssCapabilities("com.android.server"));
+    }
+
+    @Test
+    public void getGnssCapabilitiesWithPermissionsTest() {
+        final long mGnssCapabilities = 23132L;
+        when(mMockGnssCapabilitiesProvider.getGnssCapabilities()).thenReturn(mGnssCapabilities);
+        enableLocationPermissions();
+
+        assertThat(mGnssManagerService.getGnssCapabilities("com.android.server")).isEqualTo(
+                mGnssCapabilities);
+    }
+
+    @Test
+    public void getGnssBatchSizeWithoutPermissionsTest() {
+        disableLocationPermissions();
+
+        assertThrows(SecurityException.class,
+                () -> mGnssManagerService.getGnssBatchSize("com.android.server"));
+    }
+
+    @Test
+    public void getGnssBatchSizeWithPermissionsTest() {
+        final int gnssBatchSize = 10;
+        when(mMockGnssBatchingProvider.getBatchSize()).thenReturn(gnssBatchSize);
+        enableLocationPermissions();
+
+        assertThat(mGnssManagerService.getGnssBatchSize("com.android.server")).isEqualTo(
+                gnssBatchSize);
+    }
+
+    @Test
+    public void startGnssBatchWithoutPermissionsTest() {
+        final long periodNanos = 100L;
+        final boolean wakeOnFifoFull = true;
+
+        disableLocationPermissions();
+
+        assertThrows(SecurityException.class,
+                () -> mGnssManagerService.startGnssBatch(periodNanos, wakeOnFifoFull,
+                        "com.android.server"));
+        verify(mMockGnssBatchingProvider, times(0)).start(periodNanos, wakeOnFifoFull);
+    }
+
+    @Test
+    public void startGnssBatchWithPermissionsTest() {
+        final long periodNanos = 100L;
+        final boolean wakeOnFifoFull = true;
+
+        enableLocationPermissions();
+
+        assertThat(mGnssManagerService.startGnssBatch(periodNanos, wakeOnFifoFull,
+                "com.android.server"))
+                .isEqualTo(
+                        true);
+        verify(mMockGnssBatchingProvider, times(1)).start(100L, true);
+    }
+
+    @Test
+    public void addGnssBatchCallbackWithoutPermissionsTest() throws RemoteException {
+        IBatchedLocationCallback mockBatchedLocationCallback = createMockBatchedLocationCallback();
+        List<Location> mockLocationList = (List<Location>) mock(List.class);
+
+        disableLocationPermissions();
+
+        assertThrows(SecurityException.class, () -> mGnssManagerService.addGnssBatchingCallback(
+                mockBatchedLocationCallback, "com.android.server", "abcd123",
+                "TestBatchedLocationCallback"));
+
+        mGnssManagerService.onReportLocation(mockLocationList);
+
+        verify(mockBatchedLocationCallback, times(0)).onLocationBatch(mockLocationList);
+    }
+
+    @Test
+    public void addGnssBatchCallbackWithPermissionsTest() throws RemoteException {
+        IBatchedLocationCallback mockBatchedLocationCallback = createMockBatchedLocationCallback();
+        List<Location> mockLocationList = (List<Location>) mock(List.class);
+
+        enableLocationPermissions();
+
+        assertThat(mGnssManagerService.addGnssBatchingCallback(
+                mockBatchedLocationCallback, "com.android.server",
+                "abcd123", "TestBatchedLocationCallback")).isEqualTo(true);
+
+        mGnssManagerService.onReportLocation(mockLocationList);
+
+        verify(mockBatchedLocationCallback, times(1)).onLocationBatch(mockLocationList);
+    }
+
+    @Test
+    public void replaceGnssBatchCallbackTest() throws RemoteException {
+        IBatchedLocationCallback mockBatchedLocationCallback1 = createMockBatchedLocationCallback();
+        IBatchedLocationCallback mockBatchedLocationCallback2 = createMockBatchedLocationCallback();
+        List<Location> mockLocationList = (List<Location>) mock(List.class);
+
+        enableLocationPermissions();
+
+        assertThat(mGnssManagerService.addGnssBatchingCallback(
+                mockBatchedLocationCallback1, "com.android.server",
+                "abcd123", "TestBatchedLocationCallback")).isEqualTo(true);
+        assertThat(mGnssManagerService.addGnssBatchingCallback(
+                mockBatchedLocationCallback2, "com.android.server",
+                "abcd123", "TestBatchedLocationCallback")).isEqualTo(true);
+
+        mGnssManagerService.onReportLocation(mockLocationList);
+
+        verify(mockBatchedLocationCallback1, times(0)).onLocationBatch(mockLocationList);
+        verify(mockBatchedLocationCallback2, times(1)).onLocationBatch(mockLocationList);
+    }
+
+    @Test
+    public void flushGnssBatchWithoutPermissionsTest() {
+        disableLocationPermissions();
+
+        assertThrows(SecurityException.class,
+                () -> mGnssManagerService.flushGnssBatch("com.android.server"));
+        verify(mMockGnssBatchingProvider, times(0)).flush();
+    }
+
+    @Test
+    public void flushGnssBatchWithPermissionsTest() {
+        enableLocationPermissions();
+        mGnssManagerService.flushGnssBatch("com.android.server");
+
+        verify(mMockGnssBatchingProvider, times(1)).flush();
+    }
+
+    @Test
+    public void removeGnssBatchingCallbackWithoutPermissionsTest() throws RemoteException {
+        IBatchedLocationCallback mockBatchedLocationCallback = createMockBatchedLocationCallback();
+        List<Location> mockLocationList = (List<Location>) mock(List.class);
+
+        enableLocationPermissions();
+
+        mGnssManagerService.addGnssBatchingCallback(mockBatchedLocationCallback,
+                "com.android.server", "abcd123", "TestBatchedLocationCallback");
+
+        disableLocationPermissions();
+
+        assertThrows(SecurityException.class,
+                () -> mGnssManagerService.removeGnssBatchingCallback());
+
+        mGnssManagerService.onReportLocation(mockLocationList);
+
+        verify(mockBatchedLocationCallback, times(1)).onLocationBatch(mockLocationList);
+    }
+
+    @Test
+    public void removeGnssBatchingCallbackWithPermissionsTest() throws RemoteException {
+        IBatchedLocationCallback mockBatchedLocationCallback = createMockBatchedLocationCallback();
+        List<Location> mockLocationList = (List<Location>) mock(List.class);
+
+        enableLocationPermissions();
+
+        mGnssManagerService.addGnssBatchingCallback(mockBatchedLocationCallback,
+                "com.android.server", "abcd123", "TestBatchedLocationCallback");
+
+        mGnssManagerService.removeGnssBatchingCallback();
+
+        mGnssManagerService.onReportLocation(mockLocationList);
+
+        verify(mockBatchedLocationCallback, times(0)).onLocationBatch(mockLocationList);
+    }
+
+    @Test
+    public void stopGnssBatchWithoutPermissionsTest() {
+        disableLocationPermissions();
+
+        assertThrows(SecurityException.class, () -> mGnssManagerService.stopGnssBatch());
+        verify(mMockGnssBatchingProvider, times(0)).stop();
+    }
+
+    @Test
+    public void stopGnssBatchWithPermissionsTest() {
+        enableLocationPermissions();
+
+        assertThat(mGnssManagerService.stopGnssBatch()).isEqualTo(true);
+        verify(mMockGnssBatchingProvider, times(1)).stop();
+    }
+
+    @Test
+    public void registerGnssStatusCallbackWithoutPermissionsTest() throws RemoteException {
+        final int timeToFirstFix = 20000;
+        IGnssStatusListener mockGnssStatusListener = createMockGnssStatusListener();
+
+        disableLocationPermissions();
+
+        assertThrows(SecurityException.class, () -> mGnssManagerService
+                .registerGnssStatusCallback(
+                        mockGnssStatusListener, "com.android.server", "abcd123"));
+
+        mTestGnssStatusProvider.onFirstFix(timeToFirstFix);
+
+        verify(mockGnssStatusListener, times(0)).onFirstFix(timeToFirstFix);
+    }
+
+    @Test
+    public void registerGnssStatusCallbackWithPermissionsTest() throws RemoteException {
+        final int timeToFirstFix = 20000;
+        IGnssStatusListener mockGnssStatusListener = createMockGnssStatusListener();
+
+        enableLocationPermissions();
+
+        assertThat(mGnssManagerService.registerGnssStatusCallback(
+                mockGnssStatusListener, "com.android.server", "abcd123")).isEqualTo(true);
+
+        mTestGnssStatusProvider.onFirstFix(timeToFirstFix);
+
+        verify(mockGnssStatusListener, times(1)).onFirstFix(timeToFirstFix);
+    }
+
+    @Test
+    public void unregisterGnssStatusCallbackWithPermissionsTest() throws RemoteException {
+        final int timeToFirstFix = 20000;
+        IGnssStatusListener mockGnssStatusListener = createMockGnssStatusListener();
+
+        enableLocationPermissions();
+
+        mGnssManagerService.registerGnssStatusCallback(
+                mockGnssStatusListener, "com.android.server", "abcd123");
+
+        mGnssManagerService.unregisterGnssStatusCallback(mockGnssStatusListener);
+
+        mTestGnssStatusProvider.onFirstFix(timeToFirstFix);
+
+        verify(mockGnssStatusListener, times(0)).onFirstFix(timeToFirstFix);
+    }
+
+    @Test
+    public void addGnssMeasurementsListenerWithoutPermissionsTest() throws RemoteException {
+        IGnssMeasurementsListener mockGnssMeasurementsListener =
+                createMockGnssMeasurementsListener();
+        GnssMeasurementsEvent gnssMeasurementsEvent = new GnssMeasurementsEvent(new GnssClock(),
+                null);
+
+        disableLocationPermissions();
+
+        assertThrows(SecurityException.class,
+                () -> mGnssManagerService.addGnssMeasurementsListener(
+                        mockGnssMeasurementsListener,
+                        "com.android.server", "abcd123", "TestGnssMeasurementsListener"));
+
+        mTestGnssMeasurementsProvider.onMeasurementsAvailable(gnssMeasurementsEvent);
+        verify(mockGnssMeasurementsListener, times(0)).onGnssMeasurementsReceived(
+                gnssMeasurementsEvent);
+    }
+
+    @Test
+    public void addGnssMeasurementsListenerWithPermissionsTest() throws RemoteException {
+        IGnssMeasurementsListener mockGnssMeasurementsListener =
+                createMockGnssMeasurementsListener();
+        GnssMeasurementsEvent gnssMeasurementsEvent = new GnssMeasurementsEvent(new GnssClock(),
+                null);
+
+        enableLocationPermissions();
+
+        assertThat(mGnssManagerService.addGnssMeasurementsListener(mockGnssMeasurementsListener,
+                "com.android.server", "abcd123", "TestGnssMeasurementsListener")).isEqualTo(true);
+
+        mTestGnssMeasurementsProvider.onMeasurementsAvailable(gnssMeasurementsEvent);
+        verify(mockGnssMeasurementsListener, times(1)).onGnssMeasurementsReceived(
+                gnssMeasurementsEvent);
+    }
+
+    @Test
+    public void injectGnssMeasurementCorrectionsWithoutPermissionsTest() {
+        GnssMeasurementCorrections gnssMeasurementCorrections =
+                createDummyGnssMeasurementCorrections();
+
+        disableLocationPermissions();
+
+        assertThrows(SecurityException.class,
+                () -> mGnssManagerService.injectGnssMeasurementCorrections(
+                        gnssMeasurementCorrections, "com.android.server"));
+        verify(mMockGnssMeasurementCorrectionsProvider, times(0))
+                .injectGnssMeasurementCorrections(
+                        gnssMeasurementCorrections);
+    }
+
+    @Test
+    public void injectGnssMeasurementCorrectionsWithPermissionsTest() {
+        GnssMeasurementCorrections gnssMeasurementCorrections =
+                createDummyGnssMeasurementCorrections();
+
+        enableLocationPermissions();
+
+        mGnssManagerService.injectGnssMeasurementCorrections(
+                gnssMeasurementCorrections, "com.android.server");
+        verify(mMockGnssMeasurementCorrectionsProvider, times(1))
+                .injectGnssMeasurementCorrections(
+                        gnssMeasurementCorrections);
+    }
+
+    @Test
+    public void removeGnssMeasurementsListenerWithoutPermissionsTest() throws RemoteException {
+        IGnssMeasurementsListener mockGnssMeasurementsListener =
+                createMockGnssMeasurementsListener();
+        GnssMeasurementsEvent gnssMeasurementsEvent = new GnssMeasurementsEvent(new GnssClock(),
+                null);
+
+        enableLocationPermissions();
+
+        mGnssManagerService.addGnssMeasurementsListener(mockGnssMeasurementsListener,
+                "com.android.server", "abcd123", "TestGnssMeasurementsListener");
+
+        disableLocationPermissions();
+
+        mGnssManagerService.removeGnssMeasurementsListener(
+                mockGnssMeasurementsListener);
+
+        mTestGnssMeasurementsProvider.onMeasurementsAvailable(gnssMeasurementsEvent);
+        verify(mockGnssMeasurementsListener, times(0)).onGnssMeasurementsReceived(
+                gnssMeasurementsEvent);
+    }
+
+    @Test
+    public void removeGnssMeasurementsListenerWithPermissionsTest() throws RemoteException {
+        IGnssMeasurementsListener mockGnssMeasurementsListener =
+                createMockGnssMeasurementsListener();
+        GnssMeasurementsEvent gnssMeasurementsEvent = new GnssMeasurementsEvent(new GnssClock(),
+                null);
+
+        enableLocationPermissions();
+
+        mGnssManagerService.addGnssMeasurementsListener(mockGnssMeasurementsListener,
+                "com.android.server", "abcd123", "TestGnssMeasurementsListener");
+
+        disableLocationPermissions();
+
+        mGnssManagerService.removeGnssMeasurementsListener(
+                mockGnssMeasurementsListener);
+
+        mTestGnssMeasurementsProvider.onMeasurementsAvailable(gnssMeasurementsEvent);
+        verify(mockGnssMeasurementsListener, times(0)).onGnssMeasurementsReceived(
+                gnssMeasurementsEvent);
+    }
+
+    @Test
+    public void addGnssNavigationMessageListenerWithoutPermissionsTest() throws RemoteException {
+        IGnssNavigationMessageListener mockGnssNavigationMessageListener =
+                createMockGnssNavigationMessageListener();
+        GnssNavigationMessage gnssNavigationMessage = new GnssNavigationMessage();
+
+        disableLocationPermissions();
+
+        assertThrows(SecurityException.class,
+                () -> mGnssManagerService.addGnssNavigationMessageListener(
+                        mockGnssNavigationMessageListener, "com.android.server",
+                        "abcd123", "TestGnssNavigationMessageListener"));
+
+        mTestGnssNavigationMessageProvider.onNavigationMessageAvailable(gnssNavigationMessage);
+
+        verify(mockGnssNavigationMessageListener, times(0)).onGnssNavigationMessageReceived(
+                gnssNavigationMessage);
+    }
+
+    @Test
+    public void addGnssNavigationMessageListenerWithPermissionsTest() throws RemoteException {
+        IGnssNavigationMessageListener mockGnssNavigationMessageListener =
+                createMockGnssNavigationMessageListener();
+        GnssNavigationMessage gnssNavigationMessage = new GnssNavigationMessage();
+
+        enableLocationPermissions();
+
+        assertThat(mGnssManagerService.addGnssNavigationMessageListener(
+                mockGnssNavigationMessageListener, "com.android.server",
+                "abcd123", "TestGnssNavigationMessageListener")).isEqualTo(true);
+
+        mTestGnssNavigationMessageProvider.onNavigationMessageAvailable(gnssNavigationMessage);
+
+        verify(mockGnssNavigationMessageListener, times(1)).onGnssNavigationMessageReceived(
+                gnssNavigationMessage);
+    }
+
+    @Test
+    public void removeGnssNavigationMessageListenerWithoutPermissionsTest() throws RemoteException {
+        IGnssNavigationMessageListener mockGnssNavigationMessageListener =
+                createMockGnssNavigationMessageListener();
+        GnssNavigationMessage gnssNavigationMessage = new GnssNavigationMessage();
+
+        enableLocationPermissions();
+
+        mGnssManagerService.addGnssNavigationMessageListener(
+                mockGnssNavigationMessageListener, "com.android.server",
+                "abcd123", "TestGnssNavigationMessageListener");
+
+        disableLocationPermissions();
+
+        mGnssManagerService.removeGnssNavigationMessageListener(
+                mockGnssNavigationMessageListener);
+
+        mTestGnssNavigationMessageProvider.onNavigationMessageAvailable(gnssNavigationMessage);
+
+        verify(mockGnssNavigationMessageListener, times(0)).onGnssNavigationMessageReceived(
+                gnssNavigationMessage);
+    }
+
+    @Test
+    public void removeGnssNavigationMessageListenerWithPermissionsTest() throws RemoteException {
+        IGnssNavigationMessageListener mockGnssNavigationMessageListener =
+                createMockGnssNavigationMessageListener();
+        GnssNavigationMessage gnssNavigationMessage = new GnssNavigationMessage();
+
+        enableLocationPermissions();
+
+        mGnssManagerService.addGnssNavigationMessageListener(
+                mockGnssNavigationMessageListener, "com.android.server",
+                "abcd123", "TestGnssNavigationMessageListener");
+
+        mGnssManagerService.removeGnssNavigationMessageListener(
+                mockGnssNavigationMessageListener);
+
+        mTestGnssNavigationMessageProvider.onNavigationMessageAvailable(gnssNavigationMessage);
+
+        verify(mockGnssNavigationMessageListener, times(0)).onGnssNavigationMessageReceived(
+                gnssNavigationMessage);
+    }
+
+    @Test
+    public void sendNiResponseWithPermissionsTest() throws RemoteException {
+        when(mMockNetInitiatedListener.sendNiResponse(anyInt(), anyInt())).thenReturn(true);
+
+        int notifId = 0;
+        int userResponse = 0;
+        enableLocationPermissions();
+
+        assertThat(mGnssManagerService.sendNiResponse(notifId, userResponse)).isEqualTo(true);
+
+        verify(mMockNetInitiatedListener, times(1)).sendNiResponse(notifId, userResponse);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index 1ad7b6e..79af34d 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -191,7 +191,7 @@
     @After
     public void tearDown() throws Exception {
         mHandlerThread.quitSafely();
-        LocalServices.removeServiceForTest(PackageManagerInternal.class);
+        LocalServices.removeServiceForTest(PermissionManagerServiceInternal.class);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index 1edc953..49412bc0c 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -571,7 +571,8 @@
                 verifyObserverReceivedChanges(observerToTest, changesToVerify, changeItems,
                         (observer, changeItem) -> {
                             verify(observer).onUidStateChanged(changeItem.uid,
-                                    changeItem.processState, changeItem.procStateSeq);
+                                    changeItem.processState, changeItem.procStateSeq,
+                                    ActivityManager.PROCESS_CAPABILITY_NONE);
                         });
             }
             // Verify there are no other callbacks for this observer.
@@ -619,7 +620,8 @@
         // First process state message is always delivered regardless of whether the process state
         // change is above or below the cutpoint (PROCESS_STATE_SERVICE).
         verify(observer).onUidStateChanged(TEST_UID,
-                changeItem.processState, changeItem.procStateSeq);
+                changeItem.processState, changeItem.procStateSeq,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         verifyNoMoreInteractions(observer);
 
         changeItem.processState = ActivityManager.PROCESS_STATE_RECEIVER;
@@ -636,7 +638,8 @@
         // the current process state change is above cutpoint, so callback will be invoked with the
         // current process state change.
         verify(observer).onUidStateChanged(TEST_UID,
-                changeItem.processState, changeItem.procStateSeq);
+                changeItem.processState, changeItem.procStateSeq,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         verifyNoMoreInteractions(observer);
 
         changeItem.processState = ActivityManager.PROCESS_STATE_TOP;
@@ -653,7 +656,8 @@
         // the current process state change is below cutpoint, so callback will be invoked with the
         // current process state change.
         verify(observer).onUidStateChanged(TEST_UID,
-                changeItem.processState, changeItem.procStateSeq);
+                changeItem.processState, changeItem.procStateSeq,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         verifyNoMoreInteractions(observer);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
index 8965152..129d263 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
@@ -19,20 +19,34 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.app.ActivityManager;
 import android.app.ActivityManager.RecentTaskInfo;
 import android.app.IActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.os.IBinder;
+import android.os.IRemoteCallback;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
+import android.support.test.uiautomator.UiDevice;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.FlakyTest;
 
 import org.junit.Before;
 import org.junit.Test;
 
+import java.io.IOException;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Tests for {@link ActivityManager}.
@@ -43,12 +57,22 @@
 @FlakyTest(detail = "Promote to presubmit if stable")
 @Presubmit
 public class ActivityManagerTest {
+    private static final String TAG = "ActivityManagerTest";
+
+    private static final String TEST_APP = "com.android.servicestests.apps.simpleservicetestapp";
+    private static final String TEST_CLASS = TEST_APP + ".SimpleService";
+    private static final int TEST_LOOPS = 100;
+    private static final long AWAIT_TIMEOUT = 2000;
+    private static final long CHECK_INTERVAL = 100;
 
     private IActivityManager mService;
+    private IRemoteCallback mCallback;
+    private Context mContext;
 
     @Before
     public void setUp() throws Exception {
         mService = ActivityManager.getService();
+        mContext = InstrumentationRegistry.getTargetContext();
     }
 
     @Test
@@ -72,4 +96,112 @@
             }
         }
     }
+
+    @Test
+    public void testServiceUnbindAndKilling() {
+        for (int i = TEST_LOOPS; i > 0; i--) {
+            runOnce(i);
+        }
+    }
+
+    private void runOnce(long yieldDuration) {
+        final PackageManager pm = mContext.getPackageManager();
+        int uid = 0;
+        try {
+            uid = pm.getPackageUid(TEST_APP, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+
+        Intent intent = new Intent();
+        intent.setClassName(TEST_APP, TEST_CLASS);
+
+        // Create a service connection with auto creation.
+        CountDownLatch latch = new CountDownLatch(1);
+        final MyServiceConnection autoConnection = new MyServiceConnection(latch);
+        mContext.bindService(intent, autoConnection, Context.BIND_AUTO_CREATE);
+        try {
+            assertTrue("Timeout to bind to service " + intent.getComponent(),
+                    latch.await(AWAIT_TIMEOUT, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException e) {
+            fail("Unable to bind to service " + intent.getComponent());
+        }
+
+        // Create a service connection without any flags.
+        intent = new Intent();
+        intent.setClassName(TEST_APP, TEST_CLASS);
+        latch = new CountDownLatch(1);
+        MyServiceConnection otherConnection = new MyServiceConnection(latch);
+        mContext.bindService(intent, otherConnection, 0);
+        try {
+            assertTrue("Timeout to bind to service " + intent.getComponent(),
+                    latch.await(AWAIT_TIMEOUT, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException e) {
+            fail("Unable to bind to service " + intent.getComponent());
+        }
+
+        // Inform the remote process to kill itself
+        try {
+            mCallback.sendResult(null);
+            // It's basically a test for race condition, we expect the bringDownServiceLocked()
+            // would find out the hosting process is dead - to do this, technically we should
+            // do killing and unbinding simultaneously; but in reality, the killing would take
+            // a little while, before the signal really kills it; so we do it in the same thread,
+            // and even wait a while after sending killing signal.
+            Thread.sleep(yieldDuration);
+        } catch (RemoteException | InterruptedException e) {
+            fail("Unable to kill the process");
+        }
+        // Now unbind that auto connection, this should be equivalent to stopService
+        mContext.unbindService(autoConnection);
+
+        // Now we don't expect the system_server crashes.
+
+        // Wait for the target process dies
+        long total = 0;
+        for (; total < AWAIT_TIMEOUT; total += CHECK_INTERVAL) {
+            try {
+                if (!targetPackageIsRunning(mContext, uid)) {
+                    break;
+                }
+                Thread.sleep(CHECK_INTERVAL);
+            } catch (InterruptedException e) {
+            }
+        }
+        assertTrue("Timeout to wait for the target package dies", total < AWAIT_TIMEOUT);
+        mCallback = null;
+    }
+
+    private boolean targetPackageIsRunning(Context context, int uid) {
+        final String result = runShellCommand(
+                String.format("cmd activity get-uid-state %d", uid));
+        return !result.contains("(NONEXISTENT)");
+    }
+
+    private static String runShellCommand(String cmd) {
+        try {
+            return UiDevice.getInstance(
+                    InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private class MyServiceConnection implements ServiceConnection {
+        private CountDownLatch mLatch;
+
+        MyServiceConnection(CountDownLatch latch) {
+            this.mLatch = latch;
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            mCallback = IRemoteCallback.Stub.asInterface(service);
+            mLatch.countDown();
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
index d3bcff5..d12d804 100644
--- a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
@@ -181,7 +181,7 @@
     @Test
     public void testMaybeUpdateUsageStats_ProcStateFGSLocation() {
         final long elapsedTime = ZERO;
-        mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION);
+        mProcessRecord.setCurProcState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
         sService.mOomAdjuster.maybeUpdateUsageStats(mProcessRecord, elapsedTime);
 
         assertProcessRecordState(elapsedTime, false, ZERO);
diff --git a/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
index 184dc3d..a47a567 100644
--- a/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.attention;
 
+import static com.android.server.attention.AttentionManagerService.ATTENTION_CACHE_BUFFER_SIZE;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -39,6 +41,8 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.server.attention.AttentionManagerService.AttentionCheck;
+import com.android.server.attention.AttentionManagerService.AttentionCheckCache;
+import com.android.server.attention.AttentionManagerService.AttentionCheckCacheBuffer;
 import com.android.server.attention.AttentionManagerService.AttentionHandler;
 import com.android.server.attention.AttentionManagerService.UserState;
 
@@ -56,11 +60,16 @@
     private AttentionManagerService mSpyAttentionManager;
     private UserState mSpyUserState;
     private final int mTimeout = 1000;
-    @Mock private AttentionCallbackInternal mMockAttentionCallbackInternal;
-    @Mock private AttentionHandler mMockHandler;
-    @Mock private IAttentionCallback mMockIAttentionCallback;
-    @Mock private IPowerManager mMockIPowerManager;
-    @Mock Context mContext;
+    @Mock
+    private AttentionCallbackInternal mMockAttentionCallbackInternal;
+    @Mock
+    private AttentionHandler mMockHandler;
+    @Mock
+    private IAttentionCallback mMockIAttentionCallback;
+    @Mock
+    private IPowerManager mMockIPowerManager;
+    @Mock
+    Context mContext;
 
     @Before
     public void setUp() throws RemoteException {
@@ -140,12 +149,45 @@
         mSpyAttentionManager.onSwitchUser(userId);
     }
 
+    @Test
+    public void testAttentionCheckCacheBuffer_getLast_returnTheLastElement() {
+        AttentionCheckCacheBuffer buffer = new AttentionCheckCacheBuffer();
+        buffer.add(new AttentionCheckCache(0, 0, 1L));
+        AttentionCheckCache cache = new AttentionCheckCache(0, 0, 2L);
+        buffer.add(cache);
+        assertThat(buffer.getLast()).isEqualTo(cache);
+    }
+
+    @Test
+    public void testAttentionCheckCacheBuffer_get_returnNullWhenOutOfBoundary() {
+        AttentionCheckCacheBuffer buffer = new AttentionCheckCacheBuffer();
+        assertThat(buffer.get(1)).isNull();
+    }
+
+    @Test
+    public void testAttentionCheckCacheBuffer_get_handleCircularIndexing() {
+        AttentionCheckCacheBuffer buffer = new AttentionCheckCacheBuffer();
+        AttentionCheckCache cache = new AttentionCheckCache(0L, 0, 1L);
+        // Insert SIZE+1 elements.
+        for (int i = 0; i <= ATTENTION_CACHE_BUFFER_SIZE; i++) {
+            if (i == 1) {
+                buffer.add(cache);
+            } else {
+                buffer.add(new AttentionCheckCache(0L, 0, i));
+            }
+        }
+        // The element that was at index 1 should be at index 0 after inserting SIZE + 1 elements.
+        assertThat(buffer.get(0)).isEqualTo(cache);
+    }
+
     private class MockIAttentionService implements IAttentionService {
         public void checkAttention(IAttentionCallback callback) throws RemoteException {
             callback.onSuccess(0, 0);
         }
+
         public void cancelAttentionCheck(IAttentionCallback callback) {
         }
+
         public IBinder asBinder() {
             return null;
         }
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 aeccfc5..f571411 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -943,10 +943,6 @@
         verify(getServices().iactivityManager, times(1)).updateDeviceOwner(
                 eq(admin1.getPackageName()));
 
-        // TODO We should check if the caller has called clearCallerIdentity().
-        verify(getServices().ibackupManager, times(1)).setBackupServiceActive(
-                eq(UserHandle.USER_SYSTEM), eq(false));
-
         verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
                 MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
                 MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
@@ -1175,6 +1171,37 @@
         // TODO Check other calls.
     }
 
+    public void testDeviceOwnerBackupActivateDeactivate() throws Exception {
+        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+
+        // Set admin1 as a DA to the secondary user.
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
+        dpm.setActiveAdmin(admin1, /* replace =*/ false);
+        assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));
+
+        verify(getServices().ibackupManager, times(1)).setBackupServiceActive(
+                eq(UserHandle.USER_SYSTEM), eq(false));
+
+        dpm.clearDeviceOwnerApp(admin1.getPackageName());
+
+        verify(getServices().ibackupManager, times(1)).setBackupServiceActive(
+                eq(UserHandle.USER_SYSTEM), eq(true));
+    }
+
+    public void testProfileOwnerBackupActivateDeactivate() throws Exception {
+        setAsProfileOwner(admin1);
+
+        verify(getServices().ibackupManager, times(1)).setBackupServiceActive(
+                eq(DpmMockContext.CALLER_USER_HANDLE), eq(false));
+
+        dpm.clearProfileOwner(admin1);
+
+        verify(getServices().ibackupManager, times(1)).setBackupServiceActive(
+                eq(DpmMockContext.CALLER_USER_HANDLE), eq(true));
+    }
+
     public void testClearDeviceOwner_fromDifferentUser() throws Exception {
         mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
         mContext.callerPermissions.add(permission.MANAGE_USERS);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
index 16176c0..8c2d172 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
@@ -17,11 +17,13 @@
 package com.android.server.locksettings;
 
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
 
 import static junit.framework.Assert.assertEquals;
 
-import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.never;
@@ -34,6 +36,8 @@
 import static java.io.FileDescriptor.out;
 
 import android.app.ActivityManager;
+import android.app.admin.PasswordMetrics;
+import android.app.admin.PasswordPolicy;
 import android.content.Context;
 import android.os.Binder;
 import android.os.Handler;
@@ -96,8 +100,7 @@
         assertEquals(-1, mCommand.exec(mBinder, in, out, err,
                 new String[] { "set-pin", "--old", "1234" },
                 mShellCallback, mResultReceiver));
-        verify(mLockPatternUtils, never()).setLockCredential(any(), any(),
-                anyInt(), anyBoolean());
+        verify(mLockPatternUtils, never()).setLockCredential(any(), any(), anyInt());
     }
 
     @Test
@@ -109,6 +112,8 @@
                 PASSWORD_QUALITY_NUMERIC);
         when(mLockPatternUtils.checkCredential(
                 LockscreenCredential.createPin("1234"), mUserId, null)).thenReturn(true);
+        when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId))
+                .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_NUMERIC));
         assertEquals(0, mCommand.exec(new Binder(), in, out, err,
                 new String[] { "set-pin", "--old", "1234", "4321" },
                 mShellCallback, mResultReceiver));
@@ -119,6 +124,23 @@
     }
 
     @Test
+    public void testChangePin_nonCompliant() throws Exception {
+        when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
+        when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)).thenReturn(
+                PASSWORD_QUALITY_NUMERIC);
+        when(mLockPatternUtils.checkCredential(
+                LockscreenCredential.createPin("1234"), mUserId, null)).thenReturn(true);
+        when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId))
+                .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_ALPHABETIC));
+        assertEquals(-1, mCommand.exec(new Binder(), in, out, err,
+                new String[] { "set-pin", "--old", "1234", "4321" },
+                mShellCallback, mResultReceiver));
+        verify(mLockPatternUtils, never()).setLockCredential(any(), any(), anyInt());
+    }
+
+    @Test
     public void testChangePin_noLockScreen() throws Exception {
         when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(false);
         assertEquals(-1, mCommand.exec(new Binder(), in, out, err,
@@ -137,16 +159,35 @@
                 PASSWORD_QUALITY_ALPHABETIC);
         when(mLockPatternUtils.checkCredential(
                 LockscreenCredential.createPassword("1234"), mUserId, null)).thenReturn(true);
+        when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId))
+                .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_ALPHABETIC));
         assertEquals(0,  mCommand.exec(new Binder(), in, out, err,
-                new String[] { "set-password", "--old", "1234", "4321" },
+                new String[] { "set-password", "--old", "1234", "abcd" },
                 mShellCallback, mResultReceiver));
         verify(mLockPatternUtils).setLockCredential(
-                LockscreenCredential.createPassword("4321"),
+                LockscreenCredential.createPassword("abcd"),
                 LockscreenCredential.createPassword("1234"),
                 mUserId);
     }
 
     @Test
+    public void testChangePassword_nonCompliant() throws Exception {
+        when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
+        when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)).thenReturn(
+                PASSWORD_QUALITY_ALPHABETIC);
+        when(mLockPatternUtils.checkCredential(
+                LockscreenCredential.createPassword("1234"), mUserId, null)).thenReturn(true);
+        when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId))
+                .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_COMPLEX));
+        assertEquals(-1,  mCommand.exec(new Binder(), in, out, err,
+                new String[] { "set-password", "--old", "1234", "weakpassword" },
+                mShellCallback, mResultReceiver));
+        verify(mLockPatternUtils, never()).setLockCredential(any(), any(), anyInt());
+    }
+
+    @Test
     public void testChangePassword_noLockScreen() throws Exception {
         when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(false);
         assertEquals(-1,  mCommand.exec(new Binder(), in, out, err,
@@ -164,6 +205,8 @@
         when(mLockPatternUtils.checkCredential(
                 LockscreenCredential.createPattern(stringToPattern("1234")),
                 mUserId, null)).thenReturn(true);
+        when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId))
+                .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_SOMETHING));
         assertEquals(0, mCommand.exec(new Binder(), in, out, err,
                 new String[] { "set-pattern", "--old", "1234", "4321" },
                 mShellCallback, mResultReceiver));
@@ -174,6 +217,22 @@
     }
 
     @Test
+    public void testChangePattern_nonCompliant() throws Exception {
+        when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false);
+        when(mLockPatternUtils.checkCredential(
+                LockscreenCredential.createPattern(stringToPattern("1234")),
+                mUserId, null)).thenReturn(true);
+        when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId))
+                .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_NUMERIC));
+        assertEquals(-1, mCommand.exec(new Binder(), in, out, err,
+                new String[] { "set-pattern", "--old", "1234", "4321" },
+                mShellCallback, mResultReceiver));
+        verify(mLockPatternUtils, never()).setLockCredential(any(), any(), anyInt());
+    }
+
+    @Test
     public void testChangePattern_noLockScreen() throws Exception {
         when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(false);
         assertEquals(-1, mCommand.exec(new Binder(), in, out, err,
@@ -191,6 +250,8 @@
         when(mLockPatternUtils.checkCredential(
                 LockscreenCredential.createPattern(stringToPattern("1234")),
                 mUserId, null)).thenReturn(true);
+        when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId))
+                .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_UNSPECIFIED));
         assertEquals(0, mCommand.exec(new Binder(), in, out, err,
                 new String[] { "clear", "--old", "1234" },
                 mShellCallback, mResultReceiver));
@@ -200,7 +261,29 @@
                 mUserId);
     }
 
+    @Test
+    public void testClear_nonCompliant() throws Exception {
+        when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false);
+        when(mLockPatternUtils.checkCredential(
+                LockscreenCredential.createPattern(stringToPattern("1234")),
+                mUserId, null)).thenReturn(true);
+        when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId))
+                .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_SOMETHING));
+        assertEquals(-1, mCommand.exec(new Binder(), in, out, err,
+                new String[] { "clear", "--old", "1234" },
+                mShellCallback, mResultReceiver));
+        verify(mLockPatternUtils, never()).setLockCredential(any(), any(), anyInt());
+    }
+
     private List<LockPatternView.Cell> stringToPattern(String str) {
         return LockPatternUtils.byteArrayToPattern(str.getBytes());
     }
+
+    private PasswordMetrics metricsForAdminQuality(int quality) {
+        PasswordPolicy policy = new PasswordPolicy();
+        policy.quality = quality;
+        return policy.getMinMetrics();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 8a48904..51bae16 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -122,6 +122,7 @@
 import android.os.SimpleClock;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionPlan;
@@ -142,6 +143,7 @@
 import com.android.internal.util.test.BroadcastInterceptingContext.FutureIntent;
 import com.android.server.DeviceIdleInternal;
 import com.android.server.LocalServices;
+import com.android.server.usage.AppStandbyInternal;
 
 import com.google.common.util.concurrent.AbstractFuture;
 
@@ -196,6 +198,7 @@
  */
 @RunWith(AndroidJUnit4.class)
 @MediumTest
+@Presubmit
 public class NetworkPolicyManagerServiceTest {
     private static final String TAG = "NetworkPolicyManagerServiceTest";
 
@@ -295,6 +298,7 @@
 
     private void registerLocalServices() {
         addLocalServiceMock(DeviceIdleInternal.class);
+        addLocalServiceMock(AppStandbyInternal.class);
 
         final UsageStatsManagerInternal usageStats =
                 addLocalServiceMock(UsageStatsManagerInternal.class);
@@ -444,6 +448,7 @@
         LocalServices.removeServiceForTest(ActivityManagerInternal.class);
         LocalServices.removeServiceForTest(PowerManagerInternal.class);
         LocalServices.removeServiceForTest(DeviceIdleInternal.class);
+        LocalServices.removeServiceForTest(AppStandbyInternal.class);
         LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
         LocalServices.removeServiceForTest(NetworkStatsManagerInternal.class);
     }
@@ -1357,7 +1362,8 @@
 
     private void callOnUidStateChanged(int uid, int procState, long procStateSeq)
             throws Exception {
-        mUidObserver.onUidStateChanged(uid, procState, procStateSeq);
+        mUidObserver.onUidStateChanged(uid, procState, procStateSeq,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         final CountDownLatch latch = new CountDownLatch(1);
         mService.mUidEventHandler.post(() -> {
             latch.countDown();
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
new file mode 100644
index 0000000..6bb4202
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -0,0 +1,298 @@
+/*
+ * 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.server.pm;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.apex.ApexInfo;
+import android.apex.ApexSessionInfo;
+import android.apex.IApexService;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.os.FileUtils;
+import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.frameworks.servicestests.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ApexManagerTest {
+    private static final String TEST_APEX_PKG = "com.android.apex.test";
+    private static final int TEST_SESSION_ID = 99999999;
+    private static final int[] TEST_CHILD_SESSION_ID = {8888, 7777};
+    private ApexManager mApexManager;
+    private Context mContext;
+
+    private IApexService mApexService = mock(IApexService.class);
+
+    @Before
+    public void setUp() throws RemoteException {
+        mContext = InstrumentationRegistry.getInstrumentation().getContext();
+        mApexManager = new ApexManager.ApexManagerImpl(mContext, mApexService);
+    }
+
+    @Test
+    public void testGetPackageInfo_setFlagsMatchActivePackage() throws RemoteException {
+        when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));
+        final PackageInfo activePkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
+                ApexManager.MATCH_ACTIVE_PACKAGE);
+
+        assertThat(activePkgPi).isNotNull();
+        assertThat(activePkgPi.packageName).contains(TEST_APEX_PKG);
+
+        final PackageInfo factoryPkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
+                ApexManager.MATCH_FACTORY_PACKAGE);
+
+        assertThat(factoryPkgPi).isNull();
+    }
+
+    @Test
+    public void testGetPackageInfo_setFlagsMatchFactoryPackage() throws RemoteException {
+        when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+        PackageInfo factoryPkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
+                ApexManager.MATCH_FACTORY_PACKAGE);
+
+        assertThat(factoryPkgPi).isNotNull();
+        assertThat(factoryPkgPi.packageName).contains(TEST_APEX_PKG);
+
+        final PackageInfo activePkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
+                ApexManager.MATCH_ACTIVE_PACKAGE);
+
+        assertThat(activePkgPi).isNull();
+    }
+
+    @Test
+    public void testGetPackageInfo_setFlagsNone() throws RemoteException {
+        when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+
+        assertThat(mApexManager.getPackageInfo(TEST_APEX_PKG, 0)).isNull();
+    }
+
+    @Test
+    public void testGetActivePackages() throws RemoteException {
+        when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, true));
+
+        assertThat(mApexManager.getActivePackages()).isNotEmpty();
+    }
+
+    @Test
+    public void testGetActivePackages_noneActivePackages() throws RemoteException {
+        when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+
+        assertThat(mApexManager.getActivePackages()).isEmpty();
+    }
+
+    @Test
+    public void testGetFactoryPackages() throws RemoteException {
+        when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+
+        assertThat(mApexManager.getFactoryPackages()).isNotEmpty();
+    }
+
+    @Test
+    public void testGetFactoryPackages_noneFactoryPackages() throws RemoteException {
+        when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));
+
+        assertThat(mApexManager.getFactoryPackages()).isEmpty();
+    }
+
+    @Test
+    public void testGetInactivePackages() throws RemoteException {
+        when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+
+        assertThat(mApexManager.getInactivePackages()).isNotEmpty();
+    }
+
+    @Test
+    public void testGetInactivePackages_noneInactivePackages() throws RemoteException {
+        when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));
+
+        assertThat(mApexManager.getInactivePackages()).isEmpty();
+    }
+
+    @Test
+    public void testIsApexPackage() throws RemoteException {
+        when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+
+        assertThat(mApexManager.isApexPackage(TEST_APEX_PKG)).isTrue();
+    }
+
+    @Test
+    public void testIsApexSupported() {
+        assertThat(mApexManager.isApexSupported()).isTrue();
+    }
+
+    @Test
+    public void testGetStagedSessionInfo() throws RemoteException {
+        when(mApexService.getStagedSessionInfo(anyInt())).thenReturn(
+                getFakeStagedSessionInfo());
+
+        mApexManager.getStagedSessionInfo(TEST_SESSION_ID);
+        verify(mApexService, times(1)).getStagedSessionInfo(TEST_SESSION_ID);
+    }
+
+    @Test
+    public void testGetStagedSessionInfo_unKnownStagedSessionId() throws RemoteException {
+        when(mApexService.getStagedSessionInfo(anyInt())).thenReturn(
+                getFakeUnknownSessionInfo());
+
+        assertThat(mApexManager.getStagedSessionInfo(TEST_SESSION_ID)).isNull();
+    }
+
+    @Test
+    public void testSubmitStagedSession_throwPackageManagerException() throws RemoteException {
+        doAnswer(invocation -> {
+            throw new Exception();
+        }).when(mApexService).submitStagedSession(anyInt(), any(), any());
+
+        assertThrows(PackageManagerException.class,
+                () -> mApexManager.submitStagedSession(TEST_SESSION_ID, TEST_CHILD_SESSION_ID));
+    }
+
+    @Test
+    public void testSubmitStagedSession_throwRunTimeException() throws RemoteException {
+        doThrow(RemoteException.class).when(mApexService).submitStagedSession(anyInt(), any(),
+                any());
+
+        assertThrows(RuntimeException.class,
+                () -> mApexManager.submitStagedSession(TEST_SESSION_ID, TEST_CHILD_SESSION_ID));
+    }
+
+    @Test
+    public void testMarkStagedSessionReady_throwPackageManagerException() throws RemoteException {
+        doAnswer(invocation -> {
+            throw new Exception();
+        }).when(mApexService).markStagedSessionReady(anyInt());
+
+        assertThrows(PackageManagerException.class,
+                () -> mApexManager.markStagedSessionReady(TEST_SESSION_ID));
+    }
+
+    @Test
+    public void testMarkStagedSessionReady_throwRunTimeException() throws RemoteException {
+        doThrow(RemoteException.class).when(mApexService).markStagedSessionReady(anyInt());
+
+        assertThrows(RuntimeException.class,
+                () -> mApexManager.markStagedSessionReady(TEST_SESSION_ID));
+    }
+
+    @Test
+    public void testAbortActiveSession_remoteException() throws RemoteException {
+        doThrow(RemoteException.class).when(mApexService).abortActiveSession();
+
+        try {
+            assertThat(mApexManager.abortActiveSession()).isFalse();
+        } catch (Exception e) {
+            throw new AssertionError("ApexManager should not raise Exception");
+        }
+    }
+
+    @Test
+    public void testMarkStagedSessionSuccessful_throwRemoteException() throws RemoteException {
+        doThrow(RemoteException.class).when(mApexService).markStagedSessionSuccessful(anyInt());
+
+        assertThrows(RuntimeException.class,
+                () -> mApexManager.markStagedSessionSuccessful(TEST_SESSION_ID));
+    }
+
+    @Test
+    public void testUninstallApex_throwException_returnFalse() throws RemoteException {
+        doAnswer(invocation -> {
+            throw new Exception();
+        }).when(mApexService).unstagePackages(any());
+
+        assertThat(mApexManager.uninstallApex(TEST_APEX_PKG)).isFalse();
+    }
+
+    private ApexInfo[] createApexInfo(boolean isActive, boolean isFactory) {
+        File apexFile = copyRawResourceToFile(TEST_APEX_PKG, R.raw.apex_test);
+        ApexInfo apexInfo = new ApexInfo();
+        apexInfo.isActive = isActive;
+        apexInfo.isFactory = isFactory;
+        apexInfo.moduleName = TEST_APEX_PKG;
+        apexInfo.modulePath = apexFile.getPath();
+        apexInfo.versionCode = 191000070;
+
+        return new ApexInfo[]{apexInfo};
+    }
+
+    private ApexSessionInfo getFakeStagedSessionInfo() {
+        ApexSessionInfo stagedSessionInfo = new ApexSessionInfo();
+        stagedSessionInfo.sessionId = TEST_SESSION_ID;
+        stagedSessionInfo.isStaged = true;
+
+        return stagedSessionInfo;
+    }
+
+    private ApexSessionInfo getFakeUnknownSessionInfo() {
+        ApexSessionInfo stagedSessionInfo = new ApexSessionInfo();
+        stagedSessionInfo.sessionId = TEST_SESSION_ID;
+        stagedSessionInfo.isUnknown = true;
+
+        return stagedSessionInfo;
+    }
+
+    /**
+     * Copies a specified {@code resourceId} to a temp file. Returns a non-null file if the copy
+     * succeeded
+     */
+    File copyRawResourceToFile(String baseName, int resourceId) {
+        File outFile;
+        try {
+            outFile = File.createTempFile(baseName, ".apex");
+        } catch (IOException e) {
+            throw new AssertionError("CreateTempFile IOException" + e);
+        }
+
+        try (InputStream is = mContext.getResources().openRawResource(resourceId);
+             FileOutputStream os = new FileOutputStream(outFile)) {
+            assertThat(FileUtils.copy(is, os)).isGreaterThan(0L);
+        } catch (FileNotFoundException e) {
+            throw new AssertionError("File not found exception " + e);
+        } catch (IOException e) {
+            throw new AssertionError("IOException" + e);
+        }
+
+        return outFile;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index b806180..f9fc3a1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -2222,7 +2222,8 @@
     protected void makeUidForeground(int uid) {
         try {
             mService.mUidObserver.onUidStateChanged(
-                    uid, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
+                    uid, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0,
+                    ActivityManager.PROCESS_CAPABILITY_NONE);
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
@@ -2235,7 +2236,8 @@
     protected void makeUidBackground(int uid) {
         try {
             mService.mUidObserver.onUidStateChanged(
-                    uid, ActivityManager.PROCESS_STATE_TOP_SLEEPING, 0);
+                    uid, ActivityManager.PROCESS_STATE_TOP_SLEEPING, 0,
+                    ActivityManager.PROCESS_CAPABILITY_NONE);
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index fd3678d..7b101c7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -1647,7 +1647,8 @@
 
         // State changed, but not foreground, so no resetting.
         mService.mUidObserver.onUidStateChanged(
-                CALLING_UID_1, ActivityManager.PROCESS_STATE_TOP_SLEEPING, 0);
+                CALLING_UID_1, ActivityManager.PROCESS_STATE_TOP_SLEEPING, 0,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
         });
@@ -1671,7 +1672,8 @@
 
         // State changed, package1 foreground, reset.
         mService.mUidObserver.onUidStateChanged(
-                CALLING_UID_1, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
+                CALLING_UID_1, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertEquals(3, mManager.getRemainingCallCount());
         });
@@ -1691,16 +1693,19 @@
             MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
         });
         mService.mUidObserver.onUidStateChanged(
-                CALLING_UID_1, ActivityManager.PROCESS_STATE_TOP_SLEEPING, 0);
+                CALLING_UID_1, ActivityManager.PROCESS_STATE_TOP_SLEEPING, 0,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
 
         mInjectedCurrentTimeMillis++;
 
         // Different app comes to foreground briefly, and goes back to background.
         // Now, make sure package 2's counter is reset, even in this case.
         mService.mUidObserver.onUidStateChanged(
-                CALLING_UID_2, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
+                CALLING_UID_2, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         mService.mUidObserver.onUidStateChanged(
-                CALLING_UID_2, ActivityManager.PROCESS_STATE_TOP_SLEEPING, 0);
+                CALLING_UID_2, ActivityManager.PROCESS_STATE_TOP_SLEEPING, 0,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
 
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertEquals(3, mManager.getRemainingCallCount());
@@ -1731,9 +1736,11 @@
         });
 
         mService.mUidObserver.onUidStateChanged(
-                CALLING_UID_2, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
+                CALLING_UID_2, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         mService.mUidObserver.onUidStateChanged(
-                CALLING_UID_2, ActivityManager.PROCESS_STATE_TOP_SLEEPING, 0);
+                CALLING_UID_2, ActivityManager.PROCESS_STATE_TOP_SLEEPING, 0,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
 
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertEquals(3, mManager.getRemainingCallCount());
@@ -1760,7 +1767,8 @@
         // Now, also try calling some APIs and make sure foreground apps don't get throttled.
         mService.mUidObserver.onUidStateChanged(
                 UserHandle.getUid(USER_10, CALLING_UID_1),
-                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0);
+                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0,
+                ActivityManager.PROCESS_CAPABILITY_NONE);
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertEquals(3, mManager.getRemainingCallCount());
             assertFalse(mManager.isRateLimitingActive());
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
index 0196279..f08044c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -691,35 +691,16 @@
         }
     }
 
-    private boolean shouldPackageRunOob(
-            boolean isDefaultEnabled, String defaultWhitelist, String overrideEnabled,
-            String overrideWhitelist, Collection<String> packageNamesInSameProcess) {
+    private boolean shouldPackageRunOob(boolean isDefaultEnabled, String whitelist,
+            Collection<String> packageNamesInSameProcess) {
         return DexManager.isPackageSelectedToRunOobInternal(
-                isDefaultEnabled, defaultWhitelist, overrideEnabled, overrideWhitelist,
-                packageNamesInSameProcess);
+                isDefaultEnabled, whitelist, packageNamesInSameProcess);
     }
 
     @Test
-    public void testOobPackageSelectionSwitch() {
+    public void testOobPackageSelectionDefault() {
         // Feature is off by default, not overriden
-        assertFalse(shouldPackageRunOob(false, "ALL", null, null, null));
-
-        // Feature is off by default, overriden
-        assertTrue(shouldPackageRunOob(false, "ALL", "true", "ALL", null));
-        assertFalse(shouldPackageRunOob(false, "ALL", "false", null, null));
-        assertFalse(shouldPackageRunOob(false, "ALL", "false", "ALL", null));
-        assertFalse(shouldPackageRunOob(false, "ALL", "false", null, null));
-
-        // Feature is on by default, not overriden
-        assertTrue(shouldPackageRunOob(true, "ALL", null, null, null));
-        assertTrue(shouldPackageRunOob(true, "ALL", null, null, null));
-        assertTrue(shouldPackageRunOob(true, "ALL", null, "ALL", null));
-
-        // Feature is on by default, overriden
-        assertTrue(shouldPackageRunOob(true, "ALL", "true", null, null));
-        assertTrue(shouldPackageRunOob(true, "ALL", "true", "ALL", null));
-        assertFalse(shouldPackageRunOob(true, "ALL", "false", null, null));
-        assertFalse(shouldPackageRunOob(true, "ALL", "false", "ALL", null));
+        assertFalse(shouldPackageRunOob(false, "ALL", null));
     }
 
     @Test
@@ -734,24 +715,19 @@
         final Collection<String> runningPackages = Arrays.asList("com.priv.app1", "com.priv.app2");
 
         // Feature is off, whitelist does not matter
-        assertFalse(shouldPackageRunOob(false, kWhitelistApp0, null, null, runningPackages));
-        assertFalse(shouldPackageRunOob(false, kWhitelistApp1, null, null, runningPackages));
-        assertFalse(shouldPackageRunOob(false, "", null, kWhitelistApp1, runningPackages));
-        assertFalse(shouldPackageRunOob(false, "", null, "ALL", runningPackages));
-        assertFalse(shouldPackageRunOob(false, "ALL", null, "ALL", runningPackages));
-        assertFalse(shouldPackageRunOob(false, "ALL", null, "", runningPackages));
+        assertFalse(shouldPackageRunOob(false, kWhitelistApp0, runningPackages));
+        assertFalse(shouldPackageRunOob(false, kWhitelistApp1, runningPackages));
+        assertFalse(shouldPackageRunOob(false, "", runningPackages));
+        assertFalse(shouldPackageRunOob(false, "ALL", runningPackages));
 
-        // Feature is on, app not in default or overridden whitelist
-        assertFalse(shouldPackageRunOob(true, kWhitelistApp0, null, null, runningPackages));
-        assertFalse(shouldPackageRunOob(true, "", null, kWhitelistApp0, runningPackages));
-        assertFalse(shouldPackageRunOob(true, "ALL", null, kWhitelistApp0, runningPackages));
+        // Feature is on, app not in whitelist
+        assertFalse(shouldPackageRunOob(true, kWhitelistApp0, runningPackages));
+        assertFalse(shouldPackageRunOob(true, "", runningPackages));
 
-        // Feature is on, app in default or overridden whitelist
-        assertTrue(shouldPackageRunOob(true, kWhitelistApp1, null, null, runningPackages));
-        assertTrue(shouldPackageRunOob(true, kWhitelistApp2, null, null, runningPackages));
-        assertTrue(shouldPackageRunOob(true, kWhitelistApp1AndApp2, null, null, runningPackages));
-        assertTrue(shouldPackageRunOob(true, kWhitelistApp1, null, "ALL", runningPackages));
-        assertTrue(shouldPackageRunOob(true, "", null, kWhitelistApp1, runningPackages));
-        assertTrue(shouldPackageRunOob(true, "ALL", null, kWhitelistApp1, runningPackages));
+        // Feature is on, app in whitelist
+        assertTrue(shouldPackageRunOob(true, kWhitelistApp1, runningPackages));
+        assertTrue(shouldPackageRunOob(true, kWhitelistApp2, runningPackages));
+        assertTrue(shouldPackageRunOob(true, kWhitelistApp1AndApp2, runningPackages));
+        assertTrue(shouldPackageRunOob(true, "ALL", runningPackages));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
index df0c37a..e32103f 100644
--- a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
+++ b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
@@ -21,6 +21,7 @@
 import static junit.framework.TestCase.fail;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
 
 import android.app.usage.TimeSparseArray;
 import android.app.usage.UsageEvents.Event;
@@ -35,6 +36,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -423,6 +425,11 @@
         prevDB.putUsageStats(UsageStatsManager.INTERVAL_DAILY, mIntervalStats);
         // Create a backup with a specific version
         byte[] blob = prevDB.getBackupPayload(KEY_USAGE_STATS, version);
+        if (version >= 1 && version <= 3) {
+            assertFalse(blob != null && blob.length != 0,
+                    "UsageStatsDatabase shouldn't be able to write backups as XML");
+            return;
+        }
 
         clearUsageStatsFiles();
 
@@ -434,11 +441,9 @@
         List<IntervalStats> stats = newDB.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, 0, mEndTime,
                 mIntervalStatsVerifier);
 
-
-        if (version > newDB.BACKUP_VERSION || version < 1) {
-            if (stats != null && stats.size() != 0) {
-                fail("UsageStatsDatabase should ne be able to restore from unknown data versions");
-            }
+        if (version > UsageStatsDatabase.BACKUP_VERSION || version < 1) {
+            assertFalse(stats != null && !stats.isEmpty(),
+                    "UsageStatsDatabase shouldn't be able to restore from unknown data versions");
             return;
         }
 
@@ -455,9 +460,12 @@
 
     /**
      * Test the version upgrade from 3 to 4
+     *
+     * Ignored - version 3 is now deprecated.
      */
+    @Ignore
     @Test
-    public void testVersionUpgradeFrom3to4() throws IOException {
+    public void ignore_testVersionUpgradeFrom3to4() throws IOException {
         runVersionChangeTest(3, 4, UsageStatsManager.INTERVAL_DAILY);
         runVersionChangeTest(3, 4, UsageStatsManager.INTERVAL_WEEKLY);
         runVersionChangeTest(3, 4, UsageStatsManager.INTERVAL_MONTHLY);
@@ -477,9 +485,12 @@
 
     /**
      * Test the version upgrade from 3 to 5
+     *
+     * Ignored - version 3 is now deprecated.
      */
+    @Ignore
     @Test
-    public void testVersionUpgradeFrom3to5() throws IOException {
+    public void ignore_testVersionUpgradeFrom3to5() throws IOException {
         runVersionChangeTest(3, 5, UsageStatsManager.INTERVAL_DAILY);
         runVersionChangeTest(3, 5, UsageStatsManager.INTERVAL_WEEKLY);
         runVersionChangeTest(3, 5, UsageStatsManager.INTERVAL_MONTHLY);
@@ -488,13 +499,15 @@
 
 
     /**
-     * Test the version upgrade from 3 to 4
+     * Test backup/restore
      */
     @Test
     public void testBackupRestore() throws IOException {
-        runBackupRestoreTest(1);
         runBackupRestoreTest(4);
 
+        // test deprecated versions
+        runBackupRestoreTest(1);
+
         // test invalid backup versions as well
         runBackupRestoreTest(0);
         runBackupRestoreTest(99999);
diff --git a/services/tests/servicestests/test-apps/SimpleServiceTestApp/Android.bp b/services/tests/servicestests/test-apps/SimpleServiceTestApp/Android.bp
new file mode 100644
index 0000000..5cbd39c
--- /dev/null
+++ b/services/tests/servicestests/test-apps/SimpleServiceTestApp/Android.bp
@@ -0,0 +1,30 @@
+// 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.
+
+android_test_helper_app {
+    name: "SimpleServiceTestApp",
+
+    test_suites: ["device-tests"],
+
+    srcs: ["**/*.java"],
+
+    platform_apis: true,
+    certificate: "platform",
+    dex_preopt: {
+        enabled: false,
+    },
+    optimize: {
+        enabled: false,
+    },
+}
diff --git a/services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..8789992
--- /dev/null
+++ b/services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.servicestests.apps.simpleservicetestapp">
+
+    <application>
+        <service android:name=".SimpleService"
+                 android:exported="true" />
+    </application>
+
+</manifest>
diff --git a/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleService.java b/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleService.java
new file mode 100644
index 0000000..75f71d6
--- /dev/null
+++ b/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleService.java
@@ -0,0 +1,37 @@
+/*
+ * 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.servicestests.apps.simpleservicetestapp;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.IRemoteCallback;
+import android.os.Process;
+
+public class SimpleService extends Service {
+    private final IRemoteCallback.Stub mBinder = new IRemoteCallback.Stub() {
+        @Override
+        public void sendResult(Bundle bundle) {
+            Process.killProcess(Process.myPid());
+        }
+    };
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+}
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 4a9cef1..92198fa 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -55,6 +55,6 @@
         "libui",
         "libunwindstack",
         "libutils",
-        "netd_aidl_interface-V2-cpp",
+        "netd_aidl_interface-cpp",
     ],
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
new file mode 100644
index 0000000..bcff2f8
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
@@ -0,0 +1,184 @@
+/*
+ * 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.server.notification;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.NotificationHistory.HistoricalNotification;
+import android.graphics.drawable.Icon;
+import android.os.Handler;
+import android.util.AtomicFile;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+@RunWith(AndroidJUnit4.class)
+public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
+
+    File mRootDir;
+    @Mock
+    Handler mFileWriteHandler;
+
+    NotificationHistoryDatabase mDataBase;
+
+    private HistoricalNotification getHistoricalNotification(int index) {
+        return getHistoricalNotification("package" + index, index);
+    }
+
+    private HistoricalNotification getHistoricalNotification(String packageName, int index) {
+        String expectedChannelName = "channelName" + index;
+        String expectedChannelId = "channelId" + index;
+        int expectedUid = 1123456 + index;
+        int expectedUserId = 11 + index;
+        long expectedPostTime = 987654321 + index;
+        String expectedTitle = "title" + index;
+        String expectedText = "text" + index;
+        Icon expectedIcon = Icon.createWithResource(InstrumentationRegistry.getContext(),
+                index);
+
+        return new HistoricalNotification.Builder()
+                .setPackage(packageName)
+                .setChannelName(expectedChannelName)
+                .setChannelId(expectedChannelId)
+                .setUid(expectedUid)
+                .setUserId(expectedUserId)
+                .setPostedTimeMs(expectedPostTime)
+                .setTitle(expectedTitle)
+                .setText(expectedText)
+                .setIcon(expectedIcon)
+                .build();
+    }
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mRootDir = new File(mContext.getFilesDir(), "NotificationHistoryDatabaseTest");
+
+        mDataBase = new NotificationHistoryDatabase(mRootDir);
+        mDataBase.init(mFileWriteHandler);
+    }
+
+    @Test
+    public void testPrune() {
+        int retainDays = 1;
+        for (long i = 10; i >= 5; i--) {
+            File file = mock(File.class);
+            when(file.lastModified()).thenReturn(i);
+            AtomicFile af = new AtomicFile(file);
+            mDataBase.mHistoryFiles.addLast(af);
+        }
+        GregorianCalendar cal = new GregorianCalendar();
+        cal.setTimeInMillis(5);
+        cal.add(Calendar.DATE, -1 * retainDays);
+        for (int i = 5; i >= 0; i--) {
+            File file = mock(File.class);
+            when(file.lastModified()).thenReturn(cal.getTimeInMillis() - i);
+            AtomicFile af = new AtomicFile(file);
+            mDataBase.mHistoryFiles.addLast(af);
+        }
+        mDataBase.prune(retainDays, 10);
+
+        for (AtomicFile file : mDataBase.mHistoryFiles) {
+            assertThat(file.getBaseFile().lastModified() > 0);
+        }
+    }
+
+    @Test
+    public void testOnPackageRemove_posts() {
+        mDataBase.onPackageRemoved("test");
+        verify(mFileWriteHandler, times(1)).post(any());
+    }
+
+    @Test
+    public void testForceWriteToDisk() {
+        mDataBase.forceWriteToDisk();
+        verify(mFileWriteHandler, times(1)).post(any());
+    }
+
+    @Test
+    public void testOnlyOneWriteRunnableInQueue() {
+        when(mFileWriteHandler.hasCallbacks(any())).thenReturn(true);
+        mDataBase.forceWriteToDisk();
+        verify(mFileWriteHandler, never()).post(any());
+    }
+
+    @Test
+    public void testAddNotification() {
+        HistoricalNotification n = getHistoricalNotification(1);
+        HistoricalNotification n2 = getHistoricalNotification(2);
+
+        mDataBase.addNotification(n);
+        assertThat(mDataBase.mBuffer.getNotificationsToWrite()).contains(n);
+        verify(mFileWriteHandler, times(1)).postDelayed(any(), anyLong());
+
+        // second add should not trigger another write
+        mDataBase.addNotification(n2);
+        assertThat(mDataBase.mBuffer.getNotificationsToWrite()).contains(n2);
+        verify(mFileWriteHandler, times(1)).postDelayed(any(), anyLong());
+    }
+
+    @Test
+    public void testReadNotificationHistory_readsAllFiles() throws Exception {
+        for (long i = 10; i >= 5; i--) {
+            AtomicFile af = mock(AtomicFile.class);
+            mDataBase.mHistoryFiles.addLast(af);
+        }
+
+        mDataBase.readNotificationHistory();
+
+        for (AtomicFile file : mDataBase.mHistoryFiles) {
+            verify(file, times(1)).openRead();
+        }
+    }
+
+    @Test
+    public void testReadNotificationHistory_withNumFilterDoesNotReadExtraFiles() throws Exception {
+        AtomicFile af = mock(AtomicFile.class);
+        when(af.getBaseFile()).thenReturn(new File(mRootDir, "af"));
+        mDataBase.mHistoryFiles.addLast(af);
+
+        AtomicFile af2 = mock(AtomicFile.class);
+        when(af2.getBaseFile()).thenReturn(new File(mRootDir, "af2"));
+        mDataBase.mHistoryFiles.addLast(af2);
+
+        mDataBase.readNotificationHistory(null, null, 0);
+
+        verify(af, times(1)).openRead();
+        verify(af2, never()).openRead();
+    }
+
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryFilterTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryFilterTest.java
new file mode 100644
index 0000000..10bfcf1
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryFilterTest.java
@@ -0,0 +1,159 @@
+/*
+ * 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.server.notification;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.NotificationHistory;
+import android.app.NotificationHistory.HistoricalNotification;
+import android.graphics.drawable.Icon;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NotificationHistoryFilterTest extends UiServiceTestCase {
+
+    private HistoricalNotification getHistoricalNotification(int index) {
+        return getHistoricalNotification("package" + index, "channelId" + index, index);
+    }
+    private HistoricalNotification getHistoricalNotification(String pkg, int index) {
+        return getHistoricalNotification(pkg, "channelId" + index, index);
+    }
+
+    private HistoricalNotification getHistoricalNotification(String packageName, String channelId,
+            int index) {
+        String expectedChannelName = "channelName" + index;
+        int expectedUid = 1123456 + index;
+        int expectedUserId = 11 + index;
+        long expectedPostTime = 987654321 + index;
+        String expectedTitle = "title" + index;
+        String expectedText = "text" + index;
+        Icon expectedIcon = Icon.createWithResource(InstrumentationRegistry.getContext(),
+                index);
+
+        return new HistoricalNotification.Builder()
+                .setPackage(packageName)
+                .setChannelName(expectedChannelName)
+                .setChannelId(channelId)
+                .setUid(expectedUid)
+                .setUserId(expectedUserId)
+                .setPostedTimeMs(expectedPostTime)
+                .setTitle(expectedTitle)
+                .setText(expectedText)
+                .setIcon(expectedIcon)
+                .build();
+    }
+
+    @Test
+    public void testBuilder() {
+        NotificationHistoryFilter filter = new NotificationHistoryFilter.Builder()
+                .setChannel("pkg", "channel")
+                .setMaxNotifications(3)
+                .build();
+
+        assertThat(filter.getPackage()).isEqualTo("pkg");
+        assertThat(filter.getChannel()).isEqualTo("channel");
+        assertThat(filter.getMaxNotifications()).isEqualTo(3);
+    }
+
+    @Test
+    public void testMatchesCountFilter() {
+        NotificationHistoryFilter filter = new NotificationHistoryFilter.Builder()
+                .setMaxNotifications(3)
+                .build();
+
+        NotificationHistory history = new NotificationHistory();
+        assertThat(filter.matchesCountFilter(history)).isTrue();
+        history.addNotificationToWrite(getHistoricalNotification(1));
+        assertThat(filter.matchesCountFilter(history)).isTrue();
+        history.addNotificationToWrite(getHistoricalNotification(2));
+        assertThat(filter.matchesCountFilter(history)).isTrue();
+        history.addNotificationToWrite(getHistoricalNotification(3));
+        assertThat(filter.matchesCountFilter(history)).isFalse();
+    }
+
+    @Test
+    public void testMatchesCountFilter_noCountFilter() {
+        NotificationHistoryFilter filter = new NotificationHistoryFilter.Builder()
+                .build();
+
+        NotificationHistory history = new NotificationHistory();
+        assertThat(filter.matchesCountFilter(history)).isTrue();
+        history.addNotificationToWrite(getHistoricalNotification(1));
+        assertThat(filter.matchesCountFilter(history)).isTrue();
+    }
+
+    @Test
+    public void testMatchesPackageAndChannelFilter_pkgOnly() {
+        NotificationHistoryFilter filter = new NotificationHistoryFilter.Builder()
+                .setPackage("pkg")
+                .build();
+
+        HistoricalNotification hnMatches = getHistoricalNotification("pkg", 1);
+        assertThat(filter.matchesPackageAndChannelFilter(hnMatches)).isTrue();
+        HistoricalNotification hnMatches2 = getHistoricalNotification("pkg", 2);
+        assertThat(filter.matchesPackageAndChannelFilter(hnMatches2)).isTrue();
+
+        HistoricalNotification hnNoMatch = getHistoricalNotification("pkg2", 2);
+        assertThat(filter.matchesPackageAndChannelFilter(hnNoMatch)).isFalse();
+    }
+
+    @Test
+    public void testMatchesPackageAndChannelFilter_channelAlso() {
+        NotificationHistoryFilter filter = new NotificationHistoryFilter.Builder()
+                .setChannel("pkg", "channel")
+                .build();
+
+        HistoricalNotification hn1 = getHistoricalNotification("pkg", 1);
+        assertThat(filter.matchesPackageAndChannelFilter(hn1)).isFalse();
+
+        HistoricalNotification hn2 = getHistoricalNotification("pkg", "channel", 1);
+        assertThat(filter.matchesPackageAndChannelFilter(hn2)).isTrue();
+
+        HistoricalNotification hn3 = getHistoricalNotification("pkg2", "channel", 1);
+        assertThat(filter.matchesPackageAndChannelFilter(hn3)).isFalse();
+    }
+
+    @Test
+    public void testIsFiltering() {
+        NotificationHistoryFilter filter = new NotificationHistoryFilter.Builder()
+                .build();
+        assertThat(filter.isFiltering()).isFalse();
+
+        filter = new NotificationHistoryFilter.Builder()
+                .setPackage("pkg")
+                .build();
+        assertThat(filter.isFiltering()).isTrue();
+
+        filter = new NotificationHistoryFilter.Builder()
+                .setChannel("pkg", "channel")
+                .build();
+        assertThat(filter.isFiltering()).isTrue();
+
+        filter = new NotificationHistoryFilter.Builder()
+                .setMaxNotifications(5)
+                .build();
+        assertThat(filter.isFiltering()).isTrue();
+    }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryProtoHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryProtoHelperTest.java
new file mode 100644
index 0000000..458117d
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryProtoHelperTest.java
@@ -0,0 +1,297 @@
+/*
+ * 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.server.notification;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.NotificationHistory;
+import android.app.NotificationHistory.HistoricalNotification;
+import android.graphics.drawable.Icon;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NotificationHistoryProtoHelperTest extends UiServiceTestCase {
+
+    private HistoricalNotification getHistoricalNotification(int index) {
+        return getHistoricalNotification("package" + index, index);
+    }
+
+    private HistoricalNotification getHistoricalNotification(String packageName, int index) {
+        String expectedChannelName = "channelName" + index;
+        String expectedChannelId = "channelId" + index;
+        int expectedUid = 1123456 + index;
+        int expectedUserId = 11 + index;
+        long expectedPostTime = 987654321 + index;
+        String expectedTitle = "title" + index;
+        String expectedText = "text" + index;
+        Icon expectedIcon = Icon.createWithResource(InstrumentationRegistry.getContext(),
+                index);
+
+        return new HistoricalNotification.Builder()
+                .setPackage(packageName)
+                .setChannelName(expectedChannelName)
+                .setChannelId(expectedChannelId)
+                .setUid(expectedUid)
+                .setUserId(expectedUserId)
+                .setPostedTimeMs(expectedPostTime)
+                .setTitle(expectedTitle)
+                .setText(expectedText)
+                .setIcon(expectedIcon)
+                .build();
+    }
+
+    @Test
+    public void testReadWriteNotifications() throws Exception {
+        NotificationHistory history = new NotificationHistory();
+
+        List<HistoricalNotification> expectedEntries = new ArrayList<>();
+        // loops backwards just to maintain the post time newest -> oldest expectation
+        for (int i = 10; i >= 1; i--) {
+            HistoricalNotification n = getHistoricalNotification(i);
+            expectedEntries.add(n);
+            history.addNotificationToWrite(n);
+        }
+        history.poolStringsFromNotifications();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        NotificationHistoryProtoHelper.write(baos, history, 1);
+
+        NotificationHistory actualHistory = new NotificationHistory();
+        NotificationHistoryProtoHelper.read(
+                new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
+                actualHistory,
+                new NotificationHistoryFilter.Builder().build());
+
+        assertThat(actualHistory.getHistoryCount()).isEqualTo(history.getHistoryCount());
+        assertThat(actualHistory.getNotificationsToWrite())
+                .containsExactlyElementsIn(expectedEntries);
+    }
+
+    @Test
+    public void testReadWriteNotifications_stringFieldsPersistedEvenIfNoPool() throws Exception {
+        NotificationHistory history = new NotificationHistory();
+
+        List<HistoricalNotification> expectedEntries = new ArrayList<>();
+        // loops backwards just to maintain the post time newest -> oldest expectation
+        for (int i = 10; i >= 1; i--) {
+            HistoricalNotification n = getHistoricalNotification(i);
+            expectedEntries.add(n);
+            history.addNotificationToWrite(n);
+        }
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        NotificationHistoryProtoHelper.write(baos, history, 1);
+
+        NotificationHistory actualHistory = new NotificationHistory();
+        NotificationHistoryProtoHelper.read(
+                new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
+                actualHistory,
+                new NotificationHistoryFilter.Builder().build());
+
+        assertThat(actualHistory.getHistoryCount()).isEqualTo(history.getHistoryCount());
+        assertThat(actualHistory.getNotificationsToWrite())
+                .containsExactlyElementsIn(expectedEntries);
+    }
+
+    @Test
+    public void testReadNotificationsWithPkgFilter() throws Exception {
+        NotificationHistory history = new NotificationHistory();
+
+        List<HistoricalNotification> expectedEntries = new ArrayList<>();
+        Set<String> expectedStrings = new HashSet<>();
+        // loops backwards just to maintain the post time newest -> oldest expectation
+        for (int i = 10; i >= 1; i--) {
+            HistoricalNotification n =
+                    getHistoricalNotification((i % 2 == 0) ? "pkgEven" : "pkgOdd", i);
+
+            if (i % 2 == 0) {
+                expectedStrings.add(n.getPackage());
+                expectedStrings.add(n.getChannelName());
+                expectedStrings.add(n.getChannelId());
+                expectedEntries.add(n);
+            }
+            history.addNotificationToWrite(n);
+        }
+        history.poolStringsFromNotifications();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        NotificationHistoryProtoHelper.write(baos, history, 1);
+
+        NotificationHistory actualHistory = new NotificationHistory();
+
+        NotificationHistoryFilter filter = new NotificationHistoryFilter.Builder()
+                .setPackage("pkgEven")
+                .build();
+        NotificationHistoryProtoHelper.read(
+                new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
+                actualHistory,
+                filter);
+
+        assertThat(actualHistory.getNotificationsToWrite())
+                .containsExactlyElementsIn(expectedEntries);
+        assertThat(Arrays.asList(actualHistory.getPooledStringsToWrite()))
+                .containsExactlyElementsIn(expectedStrings);
+    }
+
+    @Test
+    public void testReadNotificationsWithNumberFilter() throws Exception {
+        int maxCount = 3;
+        NotificationHistory history = new NotificationHistory();
+
+        List<HistoricalNotification> expectedEntries = new ArrayList<>();
+        Set<String> expectedStrings = new HashSet<>();
+        for (int i = 1; i < 10; i++) {
+            HistoricalNotification n = getHistoricalNotification(i);
+
+            if (i <= maxCount) {
+                expectedStrings.add(n.getPackage());
+                expectedStrings.add(n.getChannelName());
+                expectedStrings.add(n.getChannelId());
+                expectedEntries.add(n);
+            }
+            history.addNotificationToWrite(n);
+        }
+        history.poolStringsFromNotifications();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        NotificationHistoryProtoHelper.write(baos, history, 1);
+
+        NotificationHistory actualHistory = new NotificationHistory();
+
+        NotificationHistoryFilter filter = new NotificationHistoryFilter.Builder()
+                .setMaxNotifications(maxCount)
+                .build();
+        NotificationHistoryProtoHelper.read(
+                new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
+                actualHistory,
+                filter);
+
+        assertThat(actualHistory.getNotificationsToWrite())
+                .containsExactlyElementsIn(expectedEntries);
+        assertThat(Arrays.asList(actualHistory.getPooledStringsToWrite()))
+                .containsExactlyElementsIn(expectedStrings);
+    }
+
+    @Test
+    public void testReadNotificationsWithNumberFilter_preExistingNotifs() throws Exception {
+        List<HistoricalNotification> expectedEntries = new ArrayList<>();
+        Set<String> expectedStrings = new HashSet<>();
+        int maxCount = 3;
+
+        NotificationHistory history = new NotificationHistory();
+        HistoricalNotification old1 = getHistoricalNotification(40);
+        history.addNotificationToWrite(old1);
+        expectedEntries.add(old1);
+
+        HistoricalNotification old2 = getHistoricalNotification(50);
+        history.addNotificationToWrite(old2);
+        expectedEntries.add(old2);
+        history.poolStringsFromNotifications();
+        expectedStrings.addAll(Arrays.asList(history.getPooledStringsToWrite()));
+
+        for (int i = 1; i < 10; i++) {
+            HistoricalNotification n = getHistoricalNotification(i);
+
+            if (i <= (maxCount - 2)) {
+                expectedStrings.add(n.getPackage());
+                expectedStrings.add(n.getChannelName());
+                expectedStrings.add(n.getChannelId());
+                expectedEntries.add(n);
+            }
+            history.addNotificationToWrite(n);
+        }
+        history.poolStringsFromNotifications();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        NotificationHistoryProtoHelper.write(baos, history, 1);
+
+        NotificationHistory actualHistory = new NotificationHistory();
+
+        NotificationHistoryFilter filter = new NotificationHistoryFilter.Builder()
+                .setMaxNotifications(maxCount)
+                .build();
+        NotificationHistoryProtoHelper.read(
+                new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
+                actualHistory,
+                filter);
+
+        assertThat(actualHistory.getNotificationsToWrite())
+                .containsExactlyElementsIn(expectedEntries);
+        assertThat(Arrays.asList(actualHistory.getPooledStringsToWrite()))
+                .containsExactlyElementsIn(expectedStrings);
+    }
+
+    @Test
+    public void testReadMergeIntoExistingHistory() throws Exception {
+        NotificationHistory history = new NotificationHistory();
+
+        List<HistoricalNotification> expectedEntries = new ArrayList<>();
+        Set<String> expectedStrings = new HashSet<>();
+        for (int i = 1; i < 10; i++) {
+            HistoricalNotification n = getHistoricalNotification(i);
+            expectedEntries.add(n);
+            expectedStrings.add(n.getPackage());
+            expectedStrings.add(n.getChannelName());
+            expectedStrings.add(n.getChannelId());
+            history.addNotificationToWrite(n);
+        }
+        history.poolStringsFromNotifications();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        NotificationHistoryProtoHelper.write(baos, history, 1);
+
+        // set up pre-existing notification history, as though read from a different file
+        NotificationHistory actualHistory = new NotificationHistory();
+        for (int i = 10; i < 20; i++) {
+            HistoricalNotification n = getHistoricalNotification(i);
+            expectedEntries.add(n);
+            expectedStrings.add(n.getPackage());
+            expectedStrings.add(n.getChannelName());
+            expectedStrings.add(n.getChannelId());
+            actualHistory.addNotificationToWrite(n);
+        }
+        actualHistory.poolStringsFromNotifications();
+
+        NotificationHistoryProtoHelper.read(
+                new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
+                actualHistory,
+                new NotificationHistoryFilter.Builder().build());
+
+        // Make sure history contains the original and new entries
+        assertThat(actualHistory.getNotificationsToWrite())
+                .containsExactlyElementsIn(expectedEntries);
+        assertThat(Arrays.asList(actualHistory.getPooledStringsToWrite()))
+                .containsExactlyElementsIn(expectedStrings);
+    }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index cd0f4f1..1ee71fb 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -5478,7 +5478,7 @@
         Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
 
         mService.mNotificationDelegate.grantInlineReplyUriPermission(
-                nr.getKey(), uri, nr.sbn.getUid());
+                nr.getKey(), uri, nr.sbn.getUser(), nr.sbn.getPackageName(), nr.sbn.getUid());
 
         // Grant permission called for the UID of SystemUI under the target user ID
         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(),
@@ -5487,6 +5487,27 @@
     }
 
     @Test
+    public void testGrantInlineReplyUriPermission_noRecordExists() throws Exception {
+        NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, 0);
+        waitForIdle();
+
+        // No notifications exist for the given record
+        StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(PKG);
+        assertEquals(0, notifsBefore.length);
+
+        Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
+        int uid = 0; // sysui on primary user
+
+        mService.mNotificationDelegate.grantInlineReplyUriPermission(
+                nr.getKey(), uri, nr.sbn.getUser(), nr.sbn.getPackageName(), nr.sbn.getUid());
+
+        // Grant permission still called if no NotificationRecord exists for the given key
+        verify(mUgm, times(1)).grantUriPermissionFromOwner(any(),
+                eq(nr.sbn.getUid()), eq(nr.sbn.getPackageName()), eq(uri), anyInt(), anyInt(),
+                eq(nr.sbn.getUserId()));
+    }
+
+    @Test
     public void testGrantInlineReplyUriPermission_userAll() throws Exception {
         // generate a NotificationRecord for USER_ALL to make sure it's converted into USER_SYSTEM
         NotificationRecord nr =
@@ -5504,7 +5525,7 @@
         Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
 
         mService.mNotificationDelegate.grantInlineReplyUriPermission(
-                nr.getKey(), uri, nr.sbn.getUid());
+                nr.getKey(), uri, nr.sbn.getUser(), nr.sbn.getPackageName(), nr.sbn.getUid());
 
         // Target user for the grant is USER_ALL instead of USER_SYSTEM
         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(),
@@ -5531,7 +5552,7 @@
         Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
 
         int uid = 0; // sysui on primary user
-        int otherUserUid = (otherUserId * 100000) + 1; // SystemUI as a different user
+        int otherUserUid = (otherUserId * 100000) + 1; // sysui as a different user
         String sysuiPackage = "sysui";
         final String[] sysuiPackages = new String[] { sysuiPackage };
         when(mPackageManager.getPackagesForUid(uid)).thenReturn(sysuiPackages);
@@ -5541,7 +5562,8 @@
         when(mPackageManager.getPackageUid(sysuiPackage, 0, otherUserId))
                 .thenReturn(otherUserUid);
 
-        mService.mNotificationDelegate.grantInlineReplyUriPermission(nr.getKey(), uri, uid);
+        mService.mNotificationDelegate.grantInlineReplyUriPermission(
+                nr.getKey(), uri, nr.sbn.getUser(), nr.sbn.getPackageName(), uid);
 
         // Target user for the grant is USER_ALL instead of USER_SYSTEM
         verify(mUgm, times(1)).grantUriPermissionFromOwner(any(),
@@ -5550,22 +5572,64 @@
     }
 
     @Test
-    public void testGrantInlineReplyUriPermission_noRecordExists() throws Exception {
-        NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
-        waitForIdle();
+    public void testClearInlineReplyUriPermission_uriRecordExists() throws Exception {
+        NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, 0);
+        reset(mPackageManager);
 
-        // No notifications exist for the given record
-        StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(PKG);
-        assertEquals(0, notifsBefore.length);
+        Uri uri1 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
+        Uri uri2 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 2);
 
-        Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
-        int uid = 0; // sysui on primary user
+        // create an inline record with two uris in it
+        mService.mNotificationDelegate.grantInlineReplyUriPermission(
+                nr.getKey(), uri1, nr.sbn.getUser(), nr.sbn.getPackageName(), nr.sbn.getUid());
+        mService.mNotificationDelegate.grantInlineReplyUriPermission(
+                nr.getKey(), uri2, nr.sbn.getUser(), nr.sbn.getPackageName(), nr.sbn.getUid());
 
-        mService.mNotificationDelegate.grantInlineReplyUriPermission(nr.getKey(), uri, uid);
+        InlineReplyUriRecord record = mService.mInlineReplyRecordsByKey.get(nr.getKey());
+        assertNotNull(record); // record exists
+        assertEquals(record.getUris().size(), 2); // record has two uris in it
 
-        // Grant permission not called if no record exists for the given key
-        verify(mUgm, times(0)).grantUriPermissionFromOwner(any(), anyInt(), any(),
-                eq(uri), anyInt(), anyInt(), anyInt());
+        mService.mNotificationDelegate.clearInlineReplyUriPermissions(nr.getKey(), nr.sbn.getUid());
+
+        // permissionOwner destroyed
+        verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(
+                eq(record.getPermissionOwner()), eq(null), eq(~0), eq(nr.getUserId()));
+    }
+
+
+    @Test
+    public void testClearInlineReplyUriPermission_noUriRecordExists() throws Exception {
+        NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, 0);
+        reset(mPackageManager);
+
+        mService.mNotificationDelegate.clearInlineReplyUriPermissions(nr.getKey(), nr.sbn.getUid());
+
+        // no permissionOwner destroyed
+        verify(mUgmInternal, times(0)).revokeUriPermissionFromOwner(
+                any(), eq(null), eq(~0), eq(nr.getUserId()));
+    }
+
+    @Test
+    public void testClearInlineReplyUriPermission_userAll() throws Exception {
+        NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
+                UserHandle.USER_ALL);
+        reset(mPackageManager);
+
+        Uri uri1 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1);
+        Uri uri2 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 2);
+
+        // create an inline record a uri in it
+        mService.mNotificationDelegate.grantInlineReplyUriPermission(
+                nr.getKey(), uri1, nr.sbn.getUser(), nr.sbn.getPackageName(), nr.sbn.getUid());
+
+        InlineReplyUriRecord record = mService.mInlineReplyRecordsByKey.get(nr.getKey());
+        assertNotNull(record); // record exists
+
+        mService.mNotificationDelegate.clearInlineReplyUriPermissions(nr.getKey(), nr.sbn.getUid());
+
+        // permissionOwner destroyed for USER_SYSTEM, not USER_ALL
+        verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(
+                eq(record.getPermissionOwner()), eq(null), eq(~0), eq(USER_SYSTEM));
     }
 
     @Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 80439cf..a1322b9 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -62,7 +62,6 @@
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
-
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.TestableContentResolver;
 import android.util.ArrayMap;
@@ -162,11 +161,11 @@
         when(testContentProvider.getIContentProvider()).thenReturn(mTestIContentProvider);
         contentResolver.addProvider(TEST_AUTHORITY, testContentProvider);
 
-        when(mTestIContentProvider.canonicalize(any(), eq(SOUND_URI)))
+        when(mTestIContentProvider.canonicalize(any(), any(), eq(SOUND_URI)))
                 .thenReturn(CANONICAL_SOUND_URI);
-        when(mTestIContentProvider.canonicalize(any(), eq(CANONICAL_SOUND_URI)))
+        when(mTestIContentProvider.canonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
                 .thenReturn(CANONICAL_SOUND_URI);
-        when(mTestIContentProvider.uncanonicalize(any(), eq(CANONICAL_SOUND_URI)))
+        when(mTestIContentProvider.uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
                 .thenReturn(SOUND_URI);
 
         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
@@ -465,7 +464,7 @@
 
         // Testing that in restore we are given the canonical version
         loadStreamXml(baos, true, UserHandle.USER_SYSTEM);
-        verify(mTestIContentProvider).uncanonicalize(any(), eq(CANONICAL_SOUND_URI));
+        verify(mTestIContentProvider).uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI));
     }
 
     @Test
@@ -475,11 +474,11 @@
                 .appendQueryParameter("title", "Test")
                 .appendQueryParameter("canonical", "1")
                 .build();
-        when(mTestIContentProvider.canonicalize(any(), eq(CANONICAL_SOUND_URI)))
+        when(mTestIContentProvider.canonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
                 .thenReturn(canonicalBasedOnLocal);
-        when(mTestIContentProvider.uncanonicalize(any(), eq(CANONICAL_SOUND_URI)))
+        when(mTestIContentProvider.uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
                 .thenReturn(localUri);
-        when(mTestIContentProvider.uncanonicalize(any(), eq(canonicalBasedOnLocal)))
+        when(mTestIContentProvider.uncanonicalize(any(), any(), eq(canonicalBasedOnLocal)))
                 .thenReturn(localUri);
 
         NotificationChannel channel =
@@ -499,9 +498,9 @@
     @Test
     public void testRestoreXml_withNonExistentCanonicalizedSoundUri() throws Exception {
         Thread.sleep(3000);
-        when(mTestIContentProvider.canonicalize(any(), eq(CANONICAL_SOUND_URI)))
+        when(mTestIContentProvider.canonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
                 .thenReturn(null);
-        when(mTestIContentProvider.uncanonicalize(any(), eq(CANONICAL_SOUND_URI)))
+        when(mTestIContentProvider.uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
                 .thenReturn(null);
 
         NotificationChannel channel =
@@ -526,7 +525,7 @@
     @Test
     public void testRestoreXml_withUncanonicalizedNonLocalSoundUri() throws Exception {
         // Not a local uncanonicalized uri, simulating that it fails to exist locally
-        when(mTestIContentProvider.canonicalize(any(), eq(SOUND_URI))).thenReturn(null);
+        when(mTestIContentProvider.canonicalize(any(), any(), eq(SOUND_URI))).thenReturn(null);
         String id = "id";
         String backupWithUncanonicalizedSoundUri = "<ranking version=\"1\">\n"
                 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
index 2abd340..8774b63 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -132,11 +132,11 @@
         when(testContentProvider.getIContentProvider()).thenReturn(mTestIContentProvider);
         contentResolver.addProvider(TEST_AUTHORITY, testContentProvider);
 
-        when(mTestIContentProvider.canonicalize(any(), eq(SOUND_URI)))
+        when(mTestIContentProvider.canonicalize(any(), any(), eq(SOUND_URI)))
                 .thenReturn(CANONICAL_SOUND_URI);
-        when(mTestIContentProvider.canonicalize(any(), eq(CANONICAL_SOUND_URI)))
+        when(mTestIContentProvider.canonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
                 .thenReturn(CANONICAL_SOUND_URI);
-        when(mTestIContentProvider.uncanonicalize(any(), eq(CANONICAL_SOUND_URI)))
+        when(mTestIContentProvider.uncanonicalize(any(), any(), eq(CANONICAL_SOUND_URI)))
                 .thenReturn(SOUND_URI);
 
         mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
index 3b336eb..aceed86 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
@@ -12,6 +12,7 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -109,8 +110,8 @@
         mPinnedSliceManager.pin("pkg", FIRST_SPECS, mToken);
         TestableLooper.get(this).processAllMessages();
 
-        verify(mIContentProvider).call(anyString(), anyString(), eq(SliceProvider.METHOD_PIN),
-                eq(null), argThat(b -> {
+        verify(mIContentProvider).call(anyString(), nullable(String.class), anyString(),
+                eq(SliceProvider.METHOD_PIN), eq(null), argThat(b -> {
                     assertEquals(TEST_URI, b.getParcelable(SliceProvider.EXTRA_BIND_URI));
                     return true;
                 }));
@@ -167,8 +168,8 @@
         // Throw exception when trying to pin
         doAnswer(invocation -> {
             throw new Exception("Pin failed");
-        }).when(mIContentProvider).call(
-                anyString(), anyString(), anyString(), eq(null), any());
+        }).when(mIContentProvider).call(anyString(), nullable(String.class), anyString(),
+                anyString(), eq(null), any());
 
         TestableLooper.get(this).processAllMessages();
 
@@ -176,8 +177,8 @@
         mPinnedSliceManager.pin("pkg", FIRST_SPECS, mToken);
         TestableLooper.get(this).processAllMessages();
 
-        verify(mIContentProvider).call(anyString(), anyString(), eq(SliceProvider.METHOD_PIN),
-                eq(null), argThat(b -> {
+        verify(mIContentProvider).call(anyString(), nullable(String.class), anyString(),
+                eq(SliceProvider.METHOD_PIN), eq(null), argThat(b -> {
                     assertEquals(TEST_URI, b.getParcelable(SliceProvider.EXTRA_BIND_URI));
                     return true;
                 }));
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index fff3221..4daf6d3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -38,9 +38,11 @@
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
 
 import android.app.TaskStackListener;
 import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
 import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
 
@@ -348,10 +350,12 @@
         final ActivityRecord activity = createFullscreenStackWithSimpleActivityAt(
                 display).topRunningActivityLocked();
         activity.setState(ActivityStack.ActivityState.RESUMED, "testHandleActivitySizeCompatMode");
+        when(activity.getRequestedOrientation()).thenReturn(
+                ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
         activity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
         activity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
-        activity.getTaskRecord().getConfiguration().windowConfiguration.setAppBounds(
-                0, 0, 1000, 2000);
+        activity.visible = true;
+        activity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
 
         final ArrayList<CompletableFuture<IBinder>> resultWrapper = new ArrayList<>();
         mService.getTaskChangeNotificationController().registerTaskStackListener(
@@ -363,11 +367,14 @@
                     }
                 });
 
-        // Expect the exact token when the activity is in size compatibility mode.
-        activity.getResolvedOverrideConfiguration().windowConfiguration.setAppBounds(
-                0, 0, 800, 1600);
         resultWrapper.add(new CompletableFuture<>());
-        display.handleActivitySizeCompatModeIfNeeded(activity);
+
+        // resize the display to exercise size-compat mode
+        final DisplayContent displayContent = display.mDisplayContent;
+        displayContent.mBaseDisplayHeight = (int) (0.8f * displayContent.mBaseDisplayHeight);
+        Configuration c = new Configuration();
+        displayContent.computeScreenConfiguration(c);
+        display.onRequestedOverrideConfigurationChanged(c);
 
         assertEquals(activity.appToken, resultWrapper.get(0).get(2, TimeUnit.SECONDS));
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 03367db..7c867b6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -149,9 +149,7 @@
     public void testOnActivityLaunchFinished() {
         onActivityLaunched();
 
-        mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(),
-                SystemClock.elapsedRealtimeNanos());
-
+        notifyTransitionStarting();
         notifyWindowsDrawn(mTopActivity);
 
         verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong());
@@ -159,10 +157,10 @@
     }
 
     @Test
-    public void testOnActivityLaunchCancelled() {
+    public void testOnActivityLaunchCancelled_hasDrawn() {
         onActivityLaunched();
 
-        mTopActivity.mDrawn = true;
+        mTopActivity.visible = mTopActivity.mDrawn = true;
 
         // Cannot time already-visible activities.
         mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
@@ -172,6 +170,28 @@
     }
 
     @Test
+    public void testOnActivityLaunchCancelled_finishedBeforeDrawn() {
+        mTopActivity.visible = mTopActivity.mDrawn = true;
+
+        // Suppress resume when creating the record because we want to notify logger manually.
+        mSupervisor.beginDeferResume();
+        // Create an activity with different process that meets process switch.
+        final ActivityRecord noDrawnActivity = new ActivityBuilder(mService)
+                .setTask(mTopActivity.getTaskRecord())
+                .setProcessName("other")
+                .build();
+        mSupervisor.readyToResume();
+
+        mActivityMetricsLogger.notifyActivityLaunching(noDrawnActivity.intent);
+        mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, noDrawnActivity);
+
+        noDrawnActivity.destroyIfPossible("test");
+        mActivityMetricsLogger.notifyVisibilityChanged(noDrawnActivity);
+
+        verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(noDrawnActivity));
+    }
+
+    @Test
     public void testOnReportFullyDrawn() {
         onActivityLaunched();
 
@@ -184,16 +204,21 @@
     private void onActivityLaunchedTrampoline() {
         onIntentStarted();
 
-        mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTopActivity);
-
-        verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTopActivity), anyInt());
-
-        // A second, distinct, activity launch is coalesced into the the current app launch sequence
         mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTrampolineActivity);
 
+        verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTrampolineActivity), anyInt());
+
+        // A second, distinct, activity launch is coalesced into the current app launch sequence.
+        mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTopActivity);
+
         verifyNoMoreInteractions(mLaunchObserver);
     }
 
+    private void notifyTransitionStarting() {
+        mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(),
+                SystemClock.elapsedRealtimeNanos());
+    }
+
     private void notifyWindowsDrawn(ActivityRecord r) {
         mActivityMetricsLogger.notifyWindowsDrawn(r.getWindowingMode(),
                 SystemClock.elapsedRealtimeNanos());
@@ -203,15 +228,12 @@
     public void testOnActivityLaunchFinishedTrampoline() {
         onActivityLaunchedTrampoline();
 
-        mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(),
-                SystemClock.elapsedRealtimeNanos());
-
+        notifyTransitionStarting();
         notifyWindowsDrawn(mTrampolineActivity);
 
         notifyWindowsDrawn(mTopActivity);
 
-        verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTrampolineActivity),
-                anyLong());
+        verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong());
         verifyNoMoreInteractions(mLaunchObserver);
     }
 
@@ -219,12 +241,12 @@
     public void testOnActivityLaunchCancelledTrampoline() {
         onActivityLaunchedTrampoline();
 
-        mTrampolineActivity.mDrawn = true;
+        mTopActivity.mDrawn = true;
 
         // Cannot time already-visible activities.
-        mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTrampolineActivity);
+        mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
 
-        verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTrampolineActivity));
+        verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTopActivity));
         verifyNoMoreInteractions(mLaunchObserver);
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index bf1508a..38d6c9c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -40,7 +40,6 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED;
 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REQUESTED;
@@ -70,10 +69,12 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.ActivityOptions;
+import android.app.WindowConfiguration;
 import android.app.servertransaction.ActivityConfigurationChangeItem;
 import android.app.servertransaction.ClientTransaction;
 import android.app.servertransaction.PauseActivityItem;
@@ -129,13 +130,13 @@
 
     @Test
     public void testStackCleanupOnClearingTask() {
-        mActivity.setTask(null);
+        mActivity.onParentChanged(null /*newParent*/, mActivity.getTask());
         verify(mStack, times(1)).onActivityRemovedFromStack(any());
     }
 
     @Test
     public void testStackCleanupOnActivityRemoval() {
-        mTask.removeActivity(mActivity);
+        mTask.mTask.removeChild(mActivity);
         verify(mStack, times(1)).onActivityRemovedFromStack(any());
     }
 
@@ -485,6 +486,43 @@
     }
 
     @Test
+    public void testSizeCompatMode_KeepBoundsWhenChangingFromFreeformToFullscreen() {
+        setupDisplayContentForCompatDisplayInsets();
+
+        // put display in freeform mode
+        ActivityDisplay display = mActivity.getDisplay();
+        final Configuration c = new Configuration(display.getRequestedOverrideConfiguration());
+        c.windowConfiguration.setBounds(new Rect(0, 0, 2000, 1000));
+        c.densityDpi = 300;
+        c.windowConfiguration.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
+        display.onRequestedOverrideConfigurationChanged(c);
+
+        // launch compat activity in freeform and store bounds
+        when(mActivity.getRequestedOrientation()).thenReturn(
+                ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+        mTask.getRequestedOverrideConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT;
+        mTask.setBounds(100, 100, 400, 600);
+        mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+        mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+        mActivity.visible = true;
+        ensureActivityConfiguration();
+
+        final Rect bounds = new Rect(mActivity.getBounds());
+        final int density = mActivity.getConfiguration().densityDpi;
+
+        // change display configuration to fullscreen
+        c.windowConfiguration.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+        display.onRequestedOverrideConfigurationChanged(c);
+
+        // check if dimensions stay the same
+        assertTrue(mActivity.inSizeCompatMode());
+        assertEquals(bounds.width(), mActivity.getBounds().width());
+        assertEquals(bounds.height(), mActivity.getBounds().height());
+        assertEquals(density, mActivity.getConfiguration().densityDpi);
+        assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN, mActivity.getWindowingMode());
+    }
+
+    @Test
     public void testSizeCompatMode_FixedAspectRatioBoundsWithDecor() {
         setupDisplayContentForCompatDisplayInsets();
         final int decorHeight = 200; // e.g. The device has cutout.
@@ -501,11 +539,17 @@
             return null;
         }).when(policy).getNonDecorInsetsLw(anyInt() /* rotation */, anyInt() /* width */,
                 anyInt() /* height */, any() /* displayCutout */, any() /* outInsets */);
+        // set appBounds to incorporate decor
+        final Configuration c =
+                new Configuration(mStack.getDisplay().getRequestedOverrideConfiguration());
+        c.windowConfiguration.getAppBounds().top = decorHeight;
+        mStack.getDisplay().onRequestedOverrideConfigurationChanged(c);
 
         doReturn(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
                 .when(mActivity).getRequestedOrientation();
         mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
         mActivity.info.minAspectRatio = mActivity.info.maxAspectRatio = 1;
+        mActivity.visible = true;
         ensureActivityConfiguration();
         // The parent configuration doesn't change since the first resolved configuration, so the
         // activity shouldn't be in the size compatibility mode.
@@ -555,7 +599,10 @@
         // Move the non-resizable activity to the new display.
         mStack.reparent(newDisplay, true /* onTop */, false /* displayRemoved */);
 
-        assertEquals(originalBounds, mActivity.getWindowConfiguration().getBounds());
+        assertEquals(originalBounds.width(),
+                mActivity.getWindowConfiguration().getBounds().width());
+        assertEquals(originalBounds.height(),
+                mActivity.getWindowConfiguration().getBounds().height());
         assertEquals(originalDpi, mActivity.getConfiguration().densityDpi);
         assertTrue(mActivity.inSizeCompatMode());
     }
@@ -566,9 +613,11 @@
         when(mActivity.getRequestedOrientation()).thenReturn(
                 ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
         mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds());
-        mTask.getConfiguration().orientation = ORIENTATION_PORTRAIT;
+        mTask.getRequestedOverrideConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT;
         mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
-        mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+        mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+        mActivity.visible = true;
+
         ensureActivityConfiguration();
         final Rect originalBounds = new Rect(mActivity.getBounds());
 
@@ -576,7 +625,10 @@
         setupDisplayAndParentSize(1000, 2000);
         ensureActivityConfiguration();
 
-        assertEquals(originalBounds, mActivity.getWindowConfiguration().getBounds());
+        assertEquals(originalBounds.width(),
+                mActivity.getWindowConfiguration().getBounds().width());
+        assertEquals(originalBounds.height(),
+                mActivity.getWindowConfiguration().getBounds().height());
         assertTrue(mActivity.inSizeCompatMode());
     }
 
@@ -584,13 +636,16 @@
     public void testSizeCompatMode_FixedScreenLayoutSizeBits() {
         final int fixedScreenLayout = Configuration.SCREENLAYOUT_LONG_NO
                 | Configuration.SCREENLAYOUT_SIZE_NORMAL;
+        final int layoutMask = Configuration.SCREENLAYOUT_LONG_MASK
+                | Configuration.SCREENLAYOUT_SIZE_MASK
+                | Configuration.SCREENLAYOUT_LAYOUTDIR_MASK;
         mTask.getRequestedOverrideConfiguration().screenLayout = fixedScreenLayout
                 | Configuration.SCREENLAYOUT_LAYOUTDIR_LTR;
         prepareFixedAspectRatioUnresizableActivity();
 
         // The initial configuration should inherit from parent.
-        assertEquals(mTask.getConfiguration().screenLayout,
-                mActivity.getConfiguration().screenLayout);
+        assertEquals(mTask.getConfiguration().screenLayout & layoutMask,
+                mActivity.getConfiguration().screenLayout & layoutMask);
 
         mTask.getConfiguration().screenLayout = Configuration.SCREENLAYOUT_LAYOUTDIR_RTL
                 | Configuration.SCREENLAYOUT_LONG_YES | Configuration.SCREENLAYOUT_SIZE_LARGE;
@@ -598,7 +653,7 @@
 
         // The size and aspect ratio bits don't change, but the layout direction should be updated.
         assertEquals(fixedScreenLayout | Configuration.SCREENLAYOUT_LAYOUTDIR_RTL,
-                mActivity.getConfiguration().screenLayout);
+                mActivity.getConfiguration().screenLayout & layoutMask);
     }
 
     @Test
@@ -618,13 +673,18 @@
                 | ActivityInfo.CONFIG_WINDOW_CONFIGURATION)
                         .when(display).getLastOverrideConfigurationChanges();
         mActivity.onConfigurationChanged(mTask.getConfiguration());
+        when(display.getLastOverrideConfigurationChanges()).thenCallRealMethod();
         // The override configuration should not change so it is still in size compatibility mode.
         assertTrue(mActivity.inSizeCompatMode());
 
-        // Simulate the display changes density.
-        doReturn(ActivityInfo.CONFIG_DENSITY).when(display).getLastOverrideConfigurationChanges();
+        // Change display density
+        final DisplayContent displayContent = mStack.getDisplay().mDisplayContent;
+        displayContent.mBaseDisplayDensity = (int) (0.7f * displayContent.mBaseDisplayDensity);
+        final Configuration c = new Configuration();
+        displayContent.computeScreenConfiguration(c);
         mService.mAmInternal = mock(ActivityManagerInternal.class);
-        mActivity.onConfigurationChanged(mTask.getConfiguration());
+        mStack.getDisplay().onRequestedOverrideConfigurationChanged(c);
+
         // The override configuration should be reset and the activity's process will be killed.
         assertFalse(mActivity.inSizeCompatMode());
         verify(mActivity).restartProcessIfVisible();
@@ -735,7 +795,7 @@
 
         // Remove activity from task
         mActivity.finishing = false;
-        mActivity.setTask(null);
+        mActivity.onParentChanged(null /*newParent*/, mActivity.getTask());
         assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_CANCELLED,
                 mActivity.finishIfPossible("test", false /* oomAdj */));
         assertFalse(mActivity.finishing);
@@ -776,6 +836,14 @@
         // Set process to 'null' to allow immediate removal, but don't call mActivity.setProcess() -
         // this will cause NPE when updating task's process.
         mActivity.app = null;
+
+        // Put a visible activity on top, so the finishing activity doesn't have to wait until the
+        // next activity reports idle to destroy it.
+        final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+        topActivity.visible = true;
+        topActivity.nowVisible = true;
+        topActivity.setState(RESUMED, "test");
+
         assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REMOVED,
                 mActivity.finishIfPossible("test", false /* oomAdj */));
         assertTrue(mActivity.finishing);
@@ -935,6 +1003,35 @@
     }
 
     /**
+     * Verify that finish request won't change the state of next top activity if the current
+     * finishing activity doesn't need to be destroyed immediately. The case is usually like
+     * from {@link ActivityStack#completePauseLocked(boolean, ActivityRecord)} to
+     * {@link ActivityRecord#completeFinishing(String)}, so the complete-pause should take the
+     * responsibility to resume the next activity with updating the state.
+     */
+    @Test
+    public void testCompleteFinishing_keepStateOfNextInvisible() {
+        final ActivityRecord currentTop = mActivity;
+        currentTop.visible = currentTop.nowVisible = true;
+
+        // Simulates that {@code currentTop} starts an existing activity from background (so its
+        // state is stopped) and the starting flow just goes to place it at top.
+        final ActivityStack nextStack = new StackBuilder(mRootActivityContainer).build();
+        final ActivityRecord nextTop = nextStack.getTopActivity();
+        nextTop.setState(STOPPED, "test");
+
+        mStack.mPausingActivity = currentTop;
+        currentTop.finishing = true;
+        currentTop.setState(PAUSED, "test");
+        currentTop.completeFinishing("completePauseLocked");
+
+        // Current top becomes stopping because it is visible and the next is invisible.
+        assertEquals(STOPPING, currentTop.getState());
+        // The state of next activity shouldn't be changed.
+        assertEquals(STOPPED, nextTop.getState());
+    }
+
+    /**
      * Verify that complete finish request for visible activity must be delayed before the next one
      * becomes visible.
      */
@@ -1042,8 +1139,11 @@
         // Add another stack to become focused and make the activity there visible. This way it
         // simulates finishing in non-focused stack in split-screen.
         final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
-        stack.getChildAt(0).getChildAt(0).nowVisible = true;
-        stack.getChildAt(0).getChildAt(0).visible = true;
+        final ActivityRecord focusedActivity = stack.getChildAt(0).getChildAt(0);
+        focusedActivity.nowVisible = true;
+        focusedActivity.visible = true;
+        focusedActivity.setState(RESUMED, "test");
+        stack.mResumedActivity = focusedActivity;
 
         topActivity.completeFinishing("test");
 
@@ -1091,6 +1191,30 @@
     }
 
     /**
+     * Verify that complete finish request for visible activity must resume next home stack before
+     * destroying it immediately if it is the last running activity on a display with a home stack.
+     * We must wait for home activity to come up to avoid a black flash in this case.
+     */
+    @Test
+    public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() {
+        // Empty the home stack.
+        final ActivityStack homeStack = mActivity.getDisplay().getHomeStack();
+        for (TaskRecord t : homeStack.getAllTasks()) {
+            homeStack.removeTask(t, "test", REMOVE_TASK_MODE_DESTROYING);
+        }
+        mActivity.finishing = true;
+        spyOn(mStack);
+
+        // Try to finish the last activity above the home stack.
+        mActivity.completeFinishing("test");
+
+        // Verify that the activity is not destroyed immediately, but waits for next one to come up.
+        verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
+        assertEquals(FINISHING, mActivity.getState());
+        assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
+    }
+
+    /**
      * Test that the activity will be moved to destroying state and the message to destroy will be
      * sent to the client.
      */
@@ -1242,6 +1366,8 @@
         c.windowConfiguration.setBounds(new Rect(0, 0, width, height));
         c.windowConfiguration.setAppBounds(0, 0, width, height);
         c.windowConfiguration.setRotation(ROTATION_0);
+        c.orientation = width > height
+                ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
         mStack.getDisplay().onRequestedOverrideConfigurationChanged(c);
         return displayContent;
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 2835c1f..fcebb81 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -1140,12 +1140,50 @@
     }
 
     @Test
+    public void testClearUnknownAppVisibilityBehindFullscreenActivity() {
+        final UnknownAppVisibilityController unknownAppVisibilityController =
+                mDefaultDisplay.mDisplayContent.mUnknownAppVisibilityController;
+        final KeyguardController keyguardController = mSupervisor.getKeyguardController();
+        doReturn(true).when(keyguardController).isKeyguardLocked();
+
+        // Start 2 activities that their processes have not yet started.
+        final ActivityRecord[] activities = new ActivityRecord[2];
+        mSupervisor.beginDeferResume();
+        for (int i = 0; i < activities.length; i++) {
+            final ActivityRecord r = new ActivityBuilder(mService).setTask(mTask).build();
+            activities[i] = r;
+            doReturn(null).when(mService).getProcessController(
+                    eq(r.processName), eq(r.info.applicationInfo.uid));
+            r.setState(ActivityStack.ActivityState.INITIALIZING, "test");
+            // Ensure precondition that the activity is opaque.
+            assertTrue(r.occludesParent());
+            mSupervisor.startSpecificActivityLocked(r, false /* andResume */,
+                    false /* checkConfig */);
+        }
+        mSupervisor.endDeferResume();
+
+        doReturn(false).when(mService).isBooting();
+        doReturn(true).when(mService).isBooted();
+        // 2 activities are started while keyguard is locked, so they are waiting to be resolved.
+        assertFalse(unknownAppVisibilityController.allResolved());
+
+        // Assume the top activity is going to resume and
+        // {@link RootActivityContainer#cancelInitializingActivities} should clear the unknown
+        // visibility records that are occluded.
+        mStack.resumeTopActivityUncheckedLocked(null /* prev */, null /* options */);
+        // Assume the top activity relayouted, just remove it directly.
+        unknownAppVisibilityController.appRemovedOrHidden(activities[1]);
+        // All unresolved records should be removed.
+        assertTrue(unknownAppVisibilityController.allResolved());
+    }
+
+    @Test
     public void testNonTopVisibleActivityNotResume() {
         final ActivityRecord nonTopVisibleActivity =
                 new ActivityBuilder(mService).setTask(mTask).build();
         new ActivityBuilder(mService).setTask(mTask).build();
         doReturn(false).when(nonTopVisibleActivity).attachedToProcess();
-        doReturn(true).when(nonTopVisibleActivity).shouldBeVisibleIgnoringKeyguard(anyBoolean());
+        doReturn(true).when(nonTopVisibleActivity).shouldBeVisible(anyBoolean(), anyBoolean());
         doNothing().when(mSupervisor).startSpecificActivityLocked(any(), anyBoolean(),
                 anyBoolean());
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 8a9423a..ace5d4e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -44,6 +44,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.ActivityDisplay.POSITION_BOTTOM;
@@ -99,6 +100,7 @@
     private ActivityStarter mStarter;
     private ActivityStartController mController;
     private ActivityMetricsLogger mActivityMetricsLogger;
+    private PackageManagerInternal mMockPackageManager;
 
     private static final int PRECONDITION_NO_CALLER_APP = 1;
     private static final int PRECONDITION_NO_INTENT_COMPONENT = 1 << 1;
@@ -359,17 +361,20 @@
         }
 
         // Set up mock package manager internal and make sure no unmocked methods are called
-        PackageManagerInternal mockPackageManager = mock(PackageManagerInternal.class,
+        mMockPackageManager = mock(PackageManagerInternal.class,
                 invocation -> {
                     throw new RuntimeException("Not stubbed");
                 });
-        doReturn(mockPackageManager).when(mService).getPackageManagerInternalLocked();
+        doReturn(mMockPackageManager).when(mService).getPackageManagerInternalLocked();
+        doReturn(false).when(mMockPackageManager).isInstantAppInstallerComponent(any());
+        doReturn(null).when(mMockPackageManager).resolveIntent(any(), any(), anyInt(), anyInt(),
+                anyBoolean(), anyInt());
 
         // Never review permissions
-        doReturn(false).when(mockPackageManager).isPermissionsReviewRequired(any(), anyInt());
-        doNothing().when(mockPackageManager).grantImplicitAccess(
+        doReturn(false).when(mMockPackageManager).isPermissionsReviewRequired(any(), anyInt());
+        doNothing().when(mMockPackageManager).grantImplicitAccess(
                 anyInt(), any(), anyInt(), anyInt());
-        doNothing().when(mockPackageManager).notifyPackageUse(anyString(), anyInt());
+        doNothing().when(mMockPackageManager).notifyPackageUse(anyString(), anyInt());
 
         final Intent intent = new Intent();
         intent.addFlags(launchFlags);
@@ -710,7 +715,7 @@
         if (startedActivity != null && startedActivity.getTaskRecord() != null) {
             // Remove the activity so it doesn't interfere with with subsequent activity launch
             // tests from this method.
-            startedActivity.getTaskRecord().removeActivity(startedActivity);
+            startedActivity.getTaskRecord().mTask.removeChild(startedActivity);
         }
     }
 
@@ -913,4 +918,46 @@
         verify(recentTasks, times(1)).setFreezeTaskListReordering();
         verify(recentTasks, times(1)).resetFreezeTaskListReorderingOnTimeout();
     }
+
+    @Test
+    public void testNoActivityInfo() {
+        final ActivityStarter starter = prepareStarter(0 /* flags */);
+        spyOn(starter.mRequest);
+
+        final Intent intent = new Intent();
+        intent.setComponent(ActivityBuilder.getDefaultComponent());
+        starter.setReason("testNoActivityInfo").setIntent(intent)
+                .setActivityInfo(null).execute();
+        verify(starter.mRequest).resolveActivity(any());
+    }
+
+    @Test
+    public void testResolveEphemeralInstaller() {
+        final ActivityStarter starter = prepareStarter(0 /* flags */);
+        final Intent intent = new Intent();
+        intent.setComponent(ActivityBuilder.getDefaultComponent());
+
+        doReturn(true).when(mMockPackageManager).isInstantAppInstallerComponent(any());
+        starter.setIntent(intent).mRequest.resolveActivity(mService.mStackSupervisor);
+
+        // Make sure the client intent won't be modified.
+        assertThat(intent.getComponent()).isNotNull();
+        assertThat(starter.getIntent().getComponent()).isNull();
+    }
+
+    @Test
+    public void testNotAllowIntentWithFd() {
+        final ActivityStarter starter = prepareStarter(0 /* flags */);
+        final Intent intent = spy(new Intent());
+        intent.setComponent(ActivityBuilder.getDefaultComponent());
+        doReturn(true).when(intent).hasFileDescriptors();
+
+        boolean exceptionCaught = false;
+        try {
+            starter.setIntent(intent).execute();
+        } catch (IllegalArgumentException ex) {
+            exceptionCaught = true;
+        }
+        assertThat(exceptionCaught).isTrue();
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 7b7e6e7..399f283 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -16,11 +16,16 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
 import android.app.Activity;
+import android.graphics.Rect;
+import android.view.WindowContainerTransaction;
 
 import androidx.test.filters.MediumTest;
 
@@ -58,5 +63,18 @@
                 mService.finishActivity(activity.appToken, 0 /* resultCode */,
                         null /* resultData */, Activity.DONT_FINISH_TASK_WITH_ACTIVITY));
     }
+
+    @Test
+    public void testTaskTransaction() {
+        removeGlobalMinSizeRestriction();
+        final ActivityStack stack = new StackBuilder(mRootActivityContainer)
+                .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+        final TaskRecord task = stack.topTask();
+        WindowContainerTransaction t = new WindowContainerTransaction();
+        Rect newBounds = new Rect(10, 10, 100, 100);
+        t.setBounds(task.mRemoteToken, new Rect(10, 10, 100, 100));
+        mService.applyContainerTransaction(t);
+        assertEquals(newBounds, task.getBounds());
+    }
 }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index d43fe63..78db6c9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -19,6 +19,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 
@@ -42,7 +43,6 @@
 import android.os.Build;
 import android.os.UserHandle;
 import android.service.voice.IVoiceInteractionSession;
-import android.util.Pair;
 import android.view.DisplayInfo;
 
 import com.android.server.AttributeCache;
@@ -118,7 +118,8 @@
         private ComponentName mComponent;
         private String mTargetActivity;
         private TaskRecord mTaskRecord;
-        private int mUid;
+        private String mProcessName = "name";
+        private int mUid = 12345;
         private boolean mCreateTask;
         private ActivityStack mStack;
         private int mActivityFlags;
@@ -175,6 +176,11 @@
             return this;
         }
 
+        ActivityBuilder setProcessName(String name) {
+            mProcessName = name;
+            return this;
+        }
+
         ActivityBuilder setUid(int uid) {
             mUid = uid;
             return this;
@@ -235,6 +241,7 @@
             aInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
             aInfo.applicationInfo.packageName = mComponent.getPackageName();
             aInfo.applicationInfo.uid = mUid;
+            aInfo.processName = mProcessName;
             aInfo.packageName = mComponent.getPackageName();
             if (mTargetActivity != null) {
                 aInfo.targetActivity = mTargetActivity;
@@ -268,7 +275,7 @@
             }
 
             final WindowProcessController wpc = new WindowProcessController(mService,
-                    mService.mContext.getApplicationInfo(), "name", 12345,
+                    mService.mContext.getApplicationInfo(), mProcessName, mUid,
                     UserHandle.getUserId(12345), mock(Object.class),
                     mock(WindowProcessListener.class));
             wpc.setThread(mock(IApplicationThread.class));
@@ -388,7 +395,7 @@
         private final RootActivityContainer mRootActivityContainer;
         private ActivityDisplay mDisplay;
         private int mStackId = -1;
-        private int mWindowingMode = WINDOWING_MODE_FULLSCREEN;
+        private int mWindowingMode = WINDOWING_MODE_UNDEFINED;
         private int mActivityType = ACTIVITY_TYPE_STANDARD;
         private boolean mOnTop = true;
         private boolean mCreateActivity = true;
diff --git a/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
index 77f9f04..b6eaab7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
@@ -21,6 +21,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyZeroInteractions;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -69,8 +70,8 @@
 
         activity1.startAnimation(activity1.getPendingTransaction(), mAdapter, false /* hidden */);
         activity2.startAnimation(activity1.getPendingTransaction(), mAdapter, false /* hidden */);
-        assertTrue(activity1.isSelfAnimating());
-        assertTrue(activity2.isSelfAnimating());
+        assertTrue(activity1.isAnimating(TRANSITION));
+        assertTrue(activity2.isAnimating(TRANSITION));
 
         // Make sure that first animation finish is deferred, second one is not deferred, and first
         // one gets cancelled.
@@ -92,8 +93,8 @@
 
         window1.startAnimation(window1.getPendingTransaction(), mAdapter, false /* hidden */);
         window2.startAnimation(window1.getPendingTransaction(), mAdapter, false /* hidden */);
-        assertTrue(window1.isSelfAnimating());
-        assertTrue(window2.isSelfAnimating());
+        assertTrue(window1.isAnimating(TRANSITION));
+        assertTrue(window2.isAnimating(TRANSITION));
 
         // Make sure that first animation finish is deferred, and removing the second window stops
         // finishes all pending deferred finishings.
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index 7449efd..1fb6a56 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -60,11 +60,9 @@
     private ActivityRecord mActivity;
 
     public void setUpOnDisplay(DisplayContent dc) {
-        mStack = createTaskStackOnDisplay(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, dc);
-        mTask = createTaskInStack(mStack, 0 /* userId */);
-        mActivity = WindowTestUtils.createTestActivityRecord(dc);
-
-        mTask.addChild(mActivity, 0);
+        mActivity = createTestActivityRecord(dc, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD);
+        mTask = mActivity.getTask();
+        mStack = mTask.mStack;
 
         // Set a remote animator with snapshot disabled. Snapshots don't work in wmtests.
         RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
@@ -167,7 +165,7 @@
         // setup currently defaults to no snapshot.
         setUpOnDisplay(mDisplayContent);
 
-        mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        mTask.mTaskRecord.setWindowingMode(WINDOWING_MODE_FREEFORM);
         assertEquals(1, mDisplayContent.mChangingApps.size());
         assertTrue(mActivity.isInChangeTransition());
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 06afce2..5f42d23 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -147,8 +147,8 @@
         // Make sure each display is in animating stage.
         assertTrue(dc1.mOpeningApps.size() > 0);
         assertTrue(dc2.mClosingApps.size() > 0);
-        assertTrue(dc1.isAppAnimating());
-        assertTrue(dc2.isAppAnimating());
+        assertTrue(dc1.isAppTransitioning());
+        assertTrue(dc2.isAppTransitioning());
     }
 
     @Test
@@ -219,10 +219,10 @@
         assertTrue(dc.mClosingApps.size() > 0);
 
         // Make sure window is in animating stage before freeze, and cancel after freeze.
-        assertTrue(dc.isAppAnimating());
+        assertTrue(dc.isAppTransitioning());
         assertFalse(runner.mCancelled);
         dc.mAppTransition.freeze();
-        assertFalse(dc.isAppAnimating());
+        assertFalse(dc.isAppTransitioning());
         assertTrue(runner.mCancelled);
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index d68aef0..2f0486d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -35,6 +35,7 @@
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
@@ -208,6 +209,9 @@
 
     @Test
     public void testSizeCompatBounds() {
+        // Disable the real configuration resolving because we only simulate partial flow.
+        // TODO: Have test use full flow.
+        doNothing().when(mTask.mTaskRecord).computeConfigResourceOverrides(any(), any());
         final Rect fixedBounds = mActivity.getRequestedOverrideConfiguration().windowConfiguration
                 .getBounds();
         fixedBounds.set(0, 0, 1200, 1600);
@@ -249,6 +253,8 @@
     @Test
     @Presubmit
     public void testGetOrientation() {
+        mActivity.setHidden(false);
+
         mActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
 
         mActivity.setOccludesParent(false);
@@ -309,6 +315,8 @@
 
     @Test
     public void testSetOrientation() {
+        mActivity.setHidden(false);
+
         // Assert orientation is unspecified to start.
         assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, mActivity.getOrientation());
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java
index e7f7d21..bcd93715 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java
@@ -334,8 +334,9 @@
         private TestConfigurationContainer mParent;
 
         TestConfigurationContainer addChild(TestConfigurationContainer childContainer) {
+            final ConfigurationContainer oldParent = childContainer.getParent();
             childContainer.mParent = this;
-            childContainer.onParentChanged();
+            childContainer.onParentChanged(this, oldParent);
             mChildren.add(childContainer);
             return childContainer;
         }
@@ -349,8 +350,9 @@
         }
 
         void removeChild(TestConfigurationContainer child) {
+            final ConfigurationContainer oldParent = child.getParent();
             child.mParent = null;
-            child.onParentChanged();
+            child.onParentChanged(null, oldParent);
         }
 
         @Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 2a3731a..67b7a66 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -24,6 +24,7 @@
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
 import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
+import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
@@ -56,15 +57,23 @@
 import android.view.DisplayInfo;
 import android.view.WindowManager;
 
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.wm.utils.WmDisplayCutout;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+/**
+ * Tests for the {@link DisplayPolicy} class.
+ *
+ * Build/Install/Run:
+ *  atest WmTests:DisplayPolicyLayoutTests
+ */
 @SmallTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
@@ -93,6 +102,12 @@
         attrs.format = PixelFormat.TRANSLUCENT;
     }
 
+    @After
+    public void tearDown() {
+        PolicyControl.setFilters("");
+        mWindow.getDisplayContent().mInputMethodTarget = null;
+    }
+
     public void setRotation(int rotation) {
         mRotation = rotation;
         updateDisplayFrames();
@@ -393,6 +408,105 @@
         assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
     }
 
+    @FlakyTest(bugId = 129711077)
+    @Test
+    public void layoutWindowLw_withImmersive_SoftInputAdjustResize() {
+        synchronized (mWm.mGlobalLock) {
+            mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_RESIZE;
+            mWindow.mAttrs.flags = 0;
+            mWindow.mAttrs.systemUiVisibility =
+                    SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                            | SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+
+            addWindow(mWindow);
+
+            mWindow.getDisplayContent().mInputMethodTarget = mWindow;
+            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+            mFrames.mContent.bottom = mFrames.mVoiceContent.bottom = INPUT_METHOD_WINDOW_TOP;
+            mFrames.mCurrent.bottom = INPUT_METHOD_WINDOW_TOP;
+            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+            int bottomInset = mFrames.mDisplayHeight - INPUT_METHOD_WINDOW_TOP;
+            assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
+            assertInsetByTopBottom(mWindow.getContentFrameLw(), 0, 0);
+            assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, bottomInset);
+        }
+    }
+
+    @FlakyTest(bugId = 129711077)
+    @Test
+    public void layoutWindowLw_withImmersive_SoftInputAdjustNothing() {
+        synchronized (mWm.mGlobalLock) {
+            mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_NOTHING;
+            mWindow.mAttrs.flags = 0;
+            mWindow.mAttrs.systemUiVisibility =
+                    SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                            | SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+
+            addWindow(mWindow);
+
+            mWindow.getDisplayContent().mInputMethodTarget = mWindow;
+            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+            mFrames.mContent.bottom = mFrames.mVoiceContent.bottom = INPUT_METHOD_WINDOW_TOP;
+            mFrames.mCurrent.bottom = INPUT_METHOD_WINDOW_TOP;
+            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+            assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
+            assertInsetByTopBottom(mWindow.getContentFrameLw(), 0, 0);
+            assertInsetByTopBottom(mWindow.getVisibleFrameLw(), 0, 0);
+        }
+    }
+
+    @FlakyTest(bugId = 129711077)
+    @Test
+    public void layoutWindowLw_withForceImmersive_fullscreen() {
+        synchronized (mWm.mGlobalLock) {
+            mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_RESIZE;
+            mWindow.mAttrs.flags = 0;
+            mWindow.mAttrs.systemUiVisibility = 0;
+            PolicyControl.setFilters(PolicyControl.NAME_IMMERSIVE_FULL + "=*");
+
+            addWindow(mWindow);
+
+            mWindow.getDisplayContent().mInputMethodTarget = mWindow;
+            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+            mFrames.mContent.bottom = mFrames.mVoiceContent.bottom = INPUT_METHOD_WINDOW_TOP;
+            mFrames.mCurrent.bottom = INPUT_METHOD_WINDOW_TOP;
+            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+            int bottomInset = mFrames.mDisplayHeight - INPUT_METHOD_WINDOW_TOP;
+            assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
+            assertInsetByTopBottom(mWindow.getContentFrameLw(), 0, 0);
+            assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, bottomInset);
+        }
+    }
+
+    @FlakyTest(bugId = 129711077)
+    @Test
+    public void layoutWindowLw_withForceImmersive_nonFullscreen() {
+        synchronized (mWm.mGlobalLock) {
+            mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_RESIZE;
+            mWindow.mAttrs.flags = 0;
+            mWindow.mAttrs.systemUiVisibility = 0;
+            mWindow.mAttrs.width = DISPLAY_WIDTH / 2;
+            mWindow.mAttrs.height = DISPLAY_HEIGHT / 2;
+            PolicyControl.setFilters(PolicyControl.NAME_IMMERSIVE_FULL + "=*");
+
+            addWindow(mWindow);
+
+            mWindow.getDisplayContent().mInputMethodTarget = mWindow;
+            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+            mFrames.mContent.bottom = mFrames.mVoiceContent.bottom = INPUT_METHOD_WINDOW_TOP;
+            mFrames.mCurrent.bottom = INPUT_METHOD_WINDOW_TOP;
+            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+            int bottomInset = mFrames.mDisplayHeight - INPUT_METHOD_WINDOW_TOP;
+            assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, bottomInset);
+            assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, bottomInset);
+            assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, bottomInset);
+        }
+    }
+
     @Test
     public void layoutHint_appWindow() {
         // Initialize DisplayFrames
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
index 2933b4a..d4558dc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
@@ -62,6 +62,7 @@
     static final int STATUS_BAR_HEIGHT = 10;
     static final int NAV_BAR_HEIGHT = 15;
     static final int DISPLAY_CUTOUT_HEIGHT = 8;
+    static final int INPUT_METHOD_WINDOW_TOP = 585;
 
     DisplayPolicy mDisplayPolicy;
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index dd85f69..5a141ae 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -410,51 +410,8 @@
     }
 
     @Test
-    public void testForceMaximizesPreDApp() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
-                WINDOWING_MODE_FREEFORM);
-
-        final ActivityOptions options = ActivityOptions.makeBasic();
-        options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
-        options.setLaunchBounds(new Rect(0, 0, 200, 100));
-
-        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
-        mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
-        mCurrent.mBounds.set(0, 0, 200, 100);
-
-        mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUPCAKE;
-
-        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
-                mActivity, /* source */ null, options, mCurrent, mResult));
-
-        assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
-                WINDOWING_MODE_FREEFORM);
-    }
-
-    @Test
-    public void testForceMaximizesAppWithoutMultipleDensitySupport() {
-        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
-                WINDOWING_MODE_FREEFORM);
-
-        final ActivityOptions options = ActivityOptions.makeBasic();
-        options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
-        options.setLaunchBounds(new Rect(0, 0, 200, 100));
-
-        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
-        mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
-        mCurrent.mBounds.set(0, 0, 200, 100);
-
-        mActivity.info.applicationInfo.flags = 0;
-
-        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
-                mActivity, /* source */ null, options, mCurrent, mResult));
-
-        assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
-                WINDOWING_MODE_FREEFORM);
-    }
-
-    @Test
     public void testForceMaximizesUnresizeableApp() {
+        mService.mSizeCompatFreeform = false;
         final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
                 WINDOWING_MODE_FREEFORM);
 
@@ -476,6 +433,33 @@
     }
 
     @Test
+    public void testLaunchesAppInWindowOnFreeformDisplay() {
+        mService.mSizeCompatFreeform = true;
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        Rect expectedLaunchBounds = new Rect(0, 0, 200, 100);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+        options.setLaunchBounds(expectedLaunchBounds);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+        mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+        mCurrent.mBounds.set(expectedLaunchBounds);
+
+        mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquals(expectedLaunchBounds, mResult.mBounds);
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+                WINDOWING_MODE_FREEFORM);
+    }
+
+    @Test
     public void testSkipsForceMaximizingAppsOnNonFreeformDisplay() {
         final ActivityOptions options = ActivityOptions.makeBasic();
         options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
index dc89f50..f8d49ad 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
@@ -64,6 +66,7 @@
                 any(InputChannel.class))).thenReturn(true);
 
         mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
+        mWindow.getTask().setResizeable(RESIZE_MODE_RESIZEABLE);
         mWindow.mInputChannel = new InputChannel();
         mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
         doReturn(mock(InputMonitor.class)).when(mDisplayContent).getInputMonitor();
@@ -129,4 +132,23 @@
         assertFalse(mTarget.isPositioningLocked());
         assertNull(mTarget.getDragWindowHandleLocked());
     }
+
+    @Test
+    public void testHandleTapOutsideNonResizableTask() {
+        assertFalse(mTarget.isPositioningLocked());
+        assertNull(mTarget.getDragWindowHandleLocked());
+
+        final DisplayContent content = mock(DisplayContent.class);
+        doReturn(mWindow.getTask()).when(content).findTaskForResizePoint(anyInt(), anyInt());
+        assertNotNull(mWindow.getTask().getTopVisibleAppMainWindow());
+
+        mWindow.getTask().setResizeable(RESIZE_MODE_UNRESIZEABLE);
+
+        mTarget.handleTapOutsideTask(content, 0, 0);
+        // Wait until the looper processes finishTaskPositioning.
+        assertTrue(waitHandlerIdle(mWm.mH, TIMEOUT_MS));
+
+        assertFalse(mTarget.isPositioningLocked());
+    }
+
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 0f8fb04..a4e38f1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -403,7 +403,9 @@
         // Without limiting to be inside the parent bounds, the out screen size should keep relative
         // to the input bounds.
         final ActivityRecord.CompatDisplayInsets compatIntsets =
-                new ActivityRecord.CompatDisplayInsets(displayContent);
+                new ActivityRecord.CompatDisplayInsets(displayContent, new Rect(0, 0,
+                        displayContent.mBaseDisplayWidth, displayContent.mBaseDisplayHeight),
+                        false);
         task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatIntsets);
 
         assertEquals((shortSide - statusBarHeight) * DENSITY_DEFAULT / parentConfig.densityDpi,
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
index 5b9a785..164d28d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -21,12 +21,16 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
@@ -119,7 +123,7 @@
     @Test
     public void testRemoveContainer() {
         final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
-        final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack);
+        final Task task = createTaskInStack(stack, 0 /* userId */);
 
         assertNotNull(stack);
         assertNotNull(task);
@@ -135,10 +139,10 @@
     @Test
     public void testRemoveContainer_deferRemoval() {
         final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
-        final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack);
+        final Task task = createTaskInStack(stack, 0 /* userId */);
 
         // Stack removal is deferred if one of its child is animating.
-        task.setLocalIsAnimating(true);
+        doReturn(true).when(task).isAnimating(TRANSITION | CHILDREN);
 
         stack.removeIfPossible();
         // For the case of deferred removal the task controller will still be connected to the its
@@ -157,8 +161,7 @@
     public void testReparent() {
         // Create first stack on primary display.
         final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
-        final WindowTestUtils.TestTask task1 = WindowTestUtils.createTestTask(stack1);
-        task1.mOnDisplayChangedCalled = false;
+        final Task task1 = createTaskInStack(stack1, 0 /* userId */);
 
         // Create second display and put second stack on it.
         final DisplayContent dc = createNewDisplay();
@@ -170,7 +173,7 @@
         final int stack1PositionInParent = stack1.getParent().mChildren.indexOf(stack1);
         final int stack2PositionInParent = stack1.getParent().mChildren.indexOf(stack2);
         assertEquals(stack1PositionInParent, stack2PositionInParent + 1);
-        assertTrue(task1.mOnDisplayChangedCalled);
+        verify(task1, times(1)).onDisplayChanged(any());
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 2ba1834..4dfa266 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -16,11 +16,16 @@
 
 package com.android.server.wm;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -45,7 +50,7 @@
     @Test
     public void testRemoveContainer() {
         final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
-        final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1);
+        final Task task = createTaskInStack(stackController1, 0 /* userId */);
         final ActivityRecord activity =
                 WindowTestUtils.createActivityRecordInTask(mDisplayContent, task);
 
@@ -59,11 +64,11 @@
     @Test
     public void testRemoveContainer_deferRemoval() {
         final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
-        final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1);
+        final Task task = createTaskInStack(stackController1, 0 /* userId */);
         final ActivityRecord activity =
                 WindowTestUtils.createActivityRecordInTask(mDisplayContent, task);
 
-        task.mShouldDeferRemoval = true;
+        doReturn(true).when(task).shouldDeferRemoval();
 
         task.removeIfPossible();
         // For the case of deferred removal the task will still be connected to the its app token
@@ -81,9 +86,9 @@
     @Test
     public void testReparent() {
         final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
-        final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stackController1);
+        final Task task = createTaskInStack(stackController1, 0 /* userId */);
         final TaskStack stackController2 = createTaskStackOnDisplay(mDisplayContent);
-        final WindowTestUtils.TestTask task2 = WindowTestUtils.createTestTask(stackController2);
+        final Task task2 = createTaskInStack(stackController2, 0 /* userId */);
 
         boolean gotException = false;
         try {
@@ -104,34 +109,33 @@
 
         task.reparent(stackController2, 0, false/* moveParents */);
         assertEquals(stackController2, task.getParent());
-        assertEquals(0, task.positionInParent());
-        assertEquals(1, task2.positionInParent());
+        assertEquals(0, task.getParent().mChildren.indexOf(task));
+        assertEquals(1, task2.getParent().mChildren.indexOf(task2));
     }
 
     @Test
     public void testReparent_BetweenDisplays() {
         // Create first stack on primary display.
         final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
-        final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack1);
-        task.mOnDisplayChangedCalled = false;
+        final Task task = createTaskInStack(stack1, 0 /* userId */);
         assertEquals(mDisplayContent, stack1.getDisplayContent());
 
         // Create second display and put second stack on it.
         final DisplayContent dc = createNewDisplay();
         final TaskStack stack2 = createTaskStackOnDisplay(dc);
-        final WindowTestUtils.TestTask task2 = WindowTestUtils.createTestTask(stack2);
+        final Task task2 = createTaskInStack(stack2, 0 /* userId */);
         // Reparent and check state
         task.reparent(stack2, 0, false /* moveParents */);
         assertEquals(stack2, task.getParent());
-        assertEquals(0, task.positionInParent());
-        assertEquals(1, task2.positionInParent());
-        assertTrue(task.mOnDisplayChangedCalled);
+        assertEquals(0, task.getParent().mChildren.indexOf(task));
+        assertEquals(1, task2.getParent().mChildren.indexOf(task2));
+        verify(task, times(1)).onDisplayChanged(any());
     }
 
     @Test
     public void testBounds() {
         final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
-        final WindowTestUtils.TestTask task = WindowTestUtils.createTestTask(stack1);
+        final Task task = createTaskInStack(stack1, 0 /* userId */);
 
         // Check that setting bounds also updates surface position
         Rect bounds = new Rect(10, 10, 100, 200);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java
index d6608f1..64ac547 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java
@@ -20,13 +20,17 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOW_CONFIG_ALWAYS_ON_TOP;
 import static android.app.WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS;
+import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS;
 import static android.app.WindowConfiguration.WINDOW_CONFIG_ROTATION;
 import static android.app.WindowConfiguration.WINDOW_CONFIG_WINDOWING_MODE;
 import static android.content.pm.ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
+import static android.view.Surface.ROTATION_270;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -218,4 +222,31 @@
         config.setActivityType(ACTIVITY_TYPE_STANDARD);
         assertTrue(config.hasWindowDecorCaption());
     }
+
+    @Test
+    public void testMaskedSetTo() {
+        final WindowConfiguration config = new WindowConfiguration();
+        final WindowConfiguration other = new WindowConfiguration();
+        other.setBounds(new Rect(10, 10, 100, 100));
+        other.setRotation(ROTATION_270);
+        config.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        config.setBounds(null);
+
+        // no change
+        config.setTo(other, 0);
+        assertTrue(config.getBounds().isEmpty());
+        assertEquals(ROTATION_UNDEFINED, config.getRotation());
+        assertEquals(WINDOWING_MODE_FULLSCREEN, config.getWindowingMode());
+
+        final int justBoundsAndRotation = WINDOW_CONFIG_BOUNDS | WINDOW_CONFIG_ROTATION;
+        config.setTo(other, justBoundsAndRotation);
+        assertEquals(other.getBounds(), config.getBounds());
+        assertEquals(other.getRotation(), config.getRotation());
+        assertEquals(WINDOWING_MODE_FULLSCREEN, config.getWindowingMode());
+
+        // unsets as well
+        final int justWindowingMode = WINDOW_CONFIG_WINDOWING_MODE;
+        config.setTo(other, justWindowingMode);
+        assertEquals(WINDOWING_MODE_UNDEFINED, config.getWindowingMode());
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 8117ff6..8536448 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -24,13 +24,18 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyFloat;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
+import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
@@ -335,7 +340,53 @@
     }
 
     @Test
-    public void testIsAnimating() {
+    public void testIsAnimating_TransitionFlag() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
+        final TestWindowContainer root = builder.setLayer(0).build();
+        final TestWindowContainer child1 = root.addChildWindow(
+                builder.setWaitForTransitionStart(true));
+
+        assertFalse(root.isAnimating(TRANSITION));
+        assertTrue(child1.isAnimating(TRANSITION));
+    }
+
+    @Test
+    public void testIsAnimating_ParentsFlag() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
+        final TestWindowContainer root = builder.setLayer(0).build();
+        final TestWindowContainer child1 = root.addChildWindow(builder);
+        final TestWindowContainer child2 = root.addChildWindow(builder.setIsAnimating(true));
+        final TestWindowContainer child21 = child2.addChildWindow(builder.setIsAnimating(false));
+
+        assertFalse(root.isAnimating());
+        assertFalse(child1.isAnimating());
+        assertFalse(child1.isAnimating(PARENTS));
+        assertTrue(child2.isAnimating());
+        assertTrue(child2.isAnimating(PARENTS));
+        assertFalse(child21.isAnimating());
+        assertTrue(child21.isAnimating(PARENTS));
+    }
+
+    @Test
+    public void testIsAnimating_ChildrenFlag() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
+        final TestWindowContainer root = builder.setLayer(0).build();
+        final TestWindowContainer child1 = root.addChildWindow(builder);
+        final TestWindowContainer child2 = root.addChildWindow(builder.setIsAnimating(true));
+        final TestWindowContainer child11 = child1.addChildWindow(builder.setIsAnimating(true));
+
+        assertFalse(root.isAnimating());
+        assertTrue(root.isAnimating(CHILDREN));
+        assertFalse(child1.isAnimating());
+        assertTrue(child1.isAnimating(CHILDREN));
+        assertTrue(child2.isAnimating());
+        assertTrue(child2.isAnimating(CHILDREN));
+        assertTrue(child11.isAnimating());
+        assertTrue(child11.isAnimating(CHILDREN));
+    }
+
+    @Test
+    public void testIsAnimating_combineFlags() {
         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).build();
 
@@ -345,19 +396,19 @@
         final TestWindowContainer child12 = child1.addChildWindow(builder.setIsAnimating(true));
         final TestWindowContainer child21 = child2.addChildWindow();
 
-        assertFalse(root.isAnimating());
-        assertTrue(child1.isAnimating());
-        assertTrue(child11.isAnimating());
-        assertTrue(child12.isAnimating());
-        assertFalse(child2.isAnimating());
-        assertFalse(child21.isAnimating());
+        assertFalse(root.isAnimating(TRANSITION | PARENTS));
+        assertTrue(child1.isAnimating(TRANSITION | PARENTS));
+        assertTrue(child11.isAnimating(TRANSITION | PARENTS));
+        assertTrue(child12.isAnimating(TRANSITION | PARENTS));
+        assertFalse(child2.isAnimating(TRANSITION | PARENTS));
+        assertFalse(child21.isAnimating(TRANSITION | PARENTS));
 
-        assertTrue(root.isSelfOrChildAnimating());
-        assertTrue(child1.isSelfOrChildAnimating());
-        assertFalse(child11.isSelfOrChildAnimating());
-        assertTrue(child12.isSelfOrChildAnimating());
-        assertFalse(child2.isSelfOrChildAnimating());
-        assertFalse(child21.isSelfOrChildAnimating());
+        assertTrue(root.isAnimating(TRANSITION | CHILDREN));
+        assertTrue(child1.isAnimating(TRANSITION | CHILDREN));
+        assertFalse(child11.isAnimating(TRANSITION | CHILDREN));
+        assertTrue(child12.isAnimating(TRANSITION | CHILDREN));
+        assertFalse(child2.isAnimating(TRANSITION | CHILDREN));
+        assertFalse(child21.isAnimating(TRANSITION | CHILDREN));
     }
 
     @Test
@@ -716,6 +767,7 @@
         private boolean mIsAnimating;
         private boolean mIsVisible;
         private boolean mFillsParent;
+        private boolean mWaitForTransitStart;
         private Integer mOrientation;
 
         private boolean mOnParentChangedCalled;
@@ -738,7 +790,7 @@
         };
 
         TestWindowContainer(WindowManagerService wm, int layer, boolean isAnimating,
-                boolean isVisible, Integer orientation) {
+                boolean isVisible, boolean waitTransitStart, Integer orientation) {
             super(wm);
 
             mLayer = layer;
@@ -746,6 +798,9 @@
             mIsVisible = isVisible;
             mFillsParent = true;
             mOrientation = orientation;
+            mWaitForTransitStart = waitTransitStart;
+            spyOn(mSurfaceAnimator);
+            doReturn(mIsAnimating).when(mSurfaceAnimator).isAnimating();
         }
 
         TestWindowContainer getParentWindow() {
@@ -772,7 +827,7 @@
         }
 
         @Override
-        void onParentChanged() {
+        void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
             mOnParentChangedCalled = true;
         }
 
@@ -783,11 +838,6 @@
         }
 
         @Override
-        boolean isSelfAnimating() {
-            return mIsAnimating;
-        }
-
-        @Override
         boolean isVisible() {
             return mIsVisible;
         }
@@ -810,6 +860,11 @@
         void setFillsParent(boolean fillsParent) {
             mFillsParent = fillsParent;
         }
+
+        @Override
+        boolean isWaitingForTransitionStart() {
+            return mWaitForTransitStart;
+        }
     }
 
     private static class TestWindowContainerBuilder {
@@ -817,6 +872,7 @@
         private int mLayer;
         private boolean mIsAnimating;
         private boolean mIsVisible;
+        private boolean mIsWaitTransitStart;
         private Integer mOrientation;
 
         TestWindowContainerBuilder(WindowManagerService wm) {
@@ -847,8 +903,14 @@
             return this;
         }
 
+        TestWindowContainerBuilder setWaitForTransitionStart(boolean waitTransitStart) {
+            mIsWaitTransitStart = waitTransitStart;
+            return this;
+        }
+
         TestWindowContainer build() {
-            return new TestWindowContainer(mWm, mLayer, mIsAnimating, mIsVisible, mOrientation);
+            return new TestWindowContainer(mWm, mLayer, mIsAnimating, mIsVisible,
+                    mIsWaitTransitStart, mOrientation);
         }
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index 5c547c2..8cd97cb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -16,24 +16,24 @@
 
 package com.android.server.wm;
 
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
 import static android.view.DisplayCutout.fromBoundingRect;
-import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
 import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
 
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.view.DisplayInfo;
 import android.view.Gravity;
-import android.view.IWindow;
 import android.view.WindowManager;
 
 import androidx.test.filters.FlakyTest;
@@ -57,29 +57,11 @@
 @RunWith(WindowTestRunner.class)
 public class WindowFrameTests extends WindowTestsBase {
 
-    private final IWindow mIWindow = new TestIWindow();
     private final Rect mEmptyRect = new Rect();
     private DisplayContent mTestDisplayContent;
 
-    static class FrameTestWindowState extends WindowState {
-        boolean mDockedResizingForTest = false;
-        FrameTestWindowState(WindowManagerService wm, IWindow iWindow, WindowToken windowToken,
-                WindowManager.LayoutParams attrs) {
-            super(wm, mock(Session.class), iWindow, windowToken, null, 0, 0, attrs, 0, 0,
-                    false /* ownerCanAddInternalSystemWindow */);
-        }
-
-        @Override
-        boolean isDockedResizing() {
-            return mDockedResizingForTest;
-        }
-    }
-
-    TaskStack mStubStack;
-
     @Before
     public void setUp() throws Exception {
-        mStubStack = mock(TaskStack.class);
         DisplayInfo testDisplayInfo = new DisplayInfo(mDisplayInfo);
         testDisplayInfo.displayCutout = null;
         mTestDisplayContent = createNewDisplay(testDisplayInfo);
@@ -129,8 +111,7 @@
                 expectedRect.bottom);
     }
 
-    private void assertPolicyCrop(
-            FrameTestWindowState w, int left, int top, int right, int bottom) {
+    private void assertPolicyCrop(WindowState w, int left, int top, int right, int bottom) {
         Rect policyCrop = new Rect();
         w.calculatePolicyCrop(policyCrop);
         assertRect(policyCrop, left, top, right, bottom);
@@ -139,7 +120,7 @@
     @Test
     public void testLayoutInFullscreenTaskInsets() {
         // fullscreen task doesn't use bounds for computeFrame
-        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+        WindowState w = createWindow();
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final int bottomContentInset = 100;
@@ -196,7 +177,7 @@
     @Test
     public void testLayoutInFullscreenTaskNoInsets() {
         // fullscreen task doesn't use bounds for computeFrame
-        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+        WindowState w = createWindow();
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         // With no insets or system decor all the frames incoming from PhoneWindowManager
@@ -278,16 +259,16 @@
         final int logicalWidth = displayInfo.logicalWidth;
         final int logicalHeight = displayInfo.logicalHeight;
 
-        final int taskLeft = logicalWidth / 4;
-        final int taskTop = logicalHeight / 4;
-        final int taskRight = logicalWidth / 4 * 3;
-        final int taskBottom = logicalHeight / 4 * 3;
-        final Rect taskBounds = new Rect(taskLeft, taskTop, taskRight, taskBottom);
-        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+        final Rect taskBounds = new Rect(
+                logicalWidth / 4, logicalHeight / 4, logicalWidth / 4 * 3, logicalHeight / 4 * 3);
+        WindowState w = createWindow();
         final Task task = w.getTask();
         // Use split-screen because it is non-fullscreen, but also not floating
-        task.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
-        task.setBounds(taskBounds);
+        task.mTaskRecord.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+        task.mTaskRecord.setBounds(taskBounds);
+        // The bounds we are requesting might be different from what the system resolved based on
+        // other factors.
+        final Rect resolvedTaskBounds = task.getBounds();
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
@@ -296,8 +277,8 @@
         w.computeFrameLw();
         // For non fullscreen tasks the containing frame is based off the
         // task bounds not the parent frame.
-        assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
-        assertContentFrame(w, taskBounds);
+        assertEquals(resolvedTaskBounds, w.getFrameLw());
+        assertContentFrame(w, resolvedTaskBounds);
         assertContentInset(w, 0, 0, 0, 0);
 
         pf.set(0, 0, logicalWidth, logicalHeight);
@@ -307,36 +288,38 @@
         final Rect cf = new Rect(0, 0, cfRight, cfBottom);
         windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
         w.computeFrameLw();
-        assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
-        int contentInsetRight = taskRight - cfRight;
-        int contentInsetBottom = taskBottom - cfBottom;
+        assertEquals(resolvedTaskBounds, w.getFrameLw());
+        int contentInsetRight = resolvedTaskBounds.right - cfRight;
+        int contentInsetBottom = resolvedTaskBounds.bottom - cfBottom;
         assertContentInset(w, 0, 0, contentInsetRight, contentInsetBottom);
-        assertContentFrame(w, new Rect(taskLeft, taskTop, taskRight - contentInsetRight,
-                taskBottom - contentInsetBottom));
+        assertContentFrame(w, new Rect(resolvedTaskBounds.left, resolvedTaskBounds.top,
+                resolvedTaskBounds.right - contentInsetRight,
+                resolvedTaskBounds.bottom - contentInsetBottom));
 
         pf.set(0, 0, logicalWidth, logicalHeight);
         // If we set displayed bounds, the insets will be computed with the main task bounds
         // but the frame will be positioned according to the displayed bounds.
         final int insetLeft = logicalWidth / 5;
         final int insetTop = logicalHeight / 5;
-        final int insetRight = insetLeft + (taskRight - taskLeft);
-        final int insetBottom = insetTop + (taskBottom - taskTop);
-        task.setOverrideDisplayedBounds(taskBounds);
-        task.setBounds(insetLeft, insetTop, insetRight, insetBottom);
+        final int insetRight = insetLeft + (resolvedTaskBounds.right - resolvedTaskBounds.left);
+        final int insetBottom = insetTop + (resolvedTaskBounds.bottom - resolvedTaskBounds.top);
+        task.mTaskRecord.setDisplayedBounds(resolvedTaskBounds);
+        task.mTaskRecord.setBounds(insetLeft, insetTop, insetRight, insetBottom);
         windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
         w.computeFrameLw();
-        assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
+        assertEquals(resolvedTaskBounds, w.getFrameLw());
         contentInsetRight = insetRight - cfRight;
         contentInsetBottom = insetBottom - cfBottom;
         assertContentInset(w, 0, 0, contentInsetRight, contentInsetBottom);
-        assertContentFrame(w, new Rect(taskLeft, taskTop, taskRight - contentInsetRight,
-                taskBottom - contentInsetBottom));
+        assertContentFrame(w, new Rect(resolvedTaskBounds.left, resolvedTaskBounds.top,
+                resolvedTaskBounds.right - contentInsetRight,
+                resolvedTaskBounds.bottom - contentInsetBottom));
     }
 
     @Test
     @FlakyTest(bugId = 130388666)
     public void testCalculatePolicyCrop() {
-        final FrameTestWindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+        final WindowState w = createWindow();
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final DisplayInfo displayInfo = w.getDisplayContent().getDisplayInfo();
@@ -381,7 +364,7 @@
         // to the computed window frame.
         assertPolicyCrop(w, 0, 0, logicalWidth / 2, logicalHeight / 2);
 
-        w.mDockedResizingForTest = true;
+        doReturn(true).when(w).isDockedResizing();
         // But if we are docked resizing it won't be, however we will still be
         // shrunk to the decor frame and the display.
         assertPolicyCrop(w, 0, 0,
@@ -402,7 +385,7 @@
         final int taskRight = logicalWidth / 4 * 3;
         final int taskBottom = logicalHeight / 4 * 3;
         final Rect taskBounds = new Rect(taskLeft, taskTop, taskRight, taskBottom);
-        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+        WindowState w = createWindow();
         final Task task = w.getTask();
         // Use split-screen because it is non-fullscreen, but also not floating
         task.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
@@ -440,7 +423,7 @@
     @FlakyTest(bugId = 130388666)
     public void testDisplayCutout() {
         // Regular fullscreen task and window
-        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+        WindowState w = createWindow();
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final Rect pf = new Rect(0, 0, 1000, 2000);
@@ -464,7 +447,7 @@
     @FlakyTest(bugId = 130388666)
     public void testDisplayCutout_tempDisplayedBounds() {
         // Regular fullscreen task and window
-        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+        WindowState w = createWindow();
         final Task task = w.getTask();
         task.setBounds(new Rect(0, 0, 1000, 2000));
         task.setOverrideDisplayedBounds(new Rect(0, -500, 1000, 1500));
@@ -489,11 +472,12 @@
 
     @Test
     public void testFreeformContentInsets() {
+        removeGlobalMinSizeRestriction();
         // fullscreen task doesn't use bounds for computeFrame
-        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+        WindowState w = createWindow();
         final Task task = w.getTask();
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
-        task.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        task.mTaskRecord.setWindowingMode(WINDOWING_MODE_FREEFORM);
 
         DisplayContent dc = mTestDisplayContent;
         dc.mInputMethodTarget = w;
@@ -515,7 +499,7 @@
         // First check that it only gets moved up enough to show window.
         final Rect winRect = new Rect(200, 200, 300, 500);
 
-        task.setBounds(winRect);
+        task.mTaskRecord.setBounds(winRect);
         w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
         w.computeFrameLw();
 
@@ -527,7 +511,7 @@
 
         // Now check that it won't get moved beyond the top and then has appropriate insets
         winRect.bottom = 600;
-        task.setBounds(winRect);
+        task.mTaskRecord.setBounds(winRect);
         w.setBounds(winRect);
         w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
         w.computeFrameLw();
@@ -544,16 +528,9 @@
         assertEquals(winRect, w.getFrameLw());
     }
 
-    private FrameTestWindowState createWindow(int width, int height) {
-        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
-        attrs.width = width;
-        attrs.height = height;
-
-        ActivityRecord activity = createActivityRecord(mTestDisplayContent,
-                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
-
-        FrameTestWindowState ws = new FrameTestWindowState(mWm, mIWindow, activity, attrs);
-        activity.addWindow(ws);
+    private WindowState createWindow() {
+        final WindowState ws = createWindow(null, TYPE_APPLICATION, mTestDisplayContent, "WindowFrameTests");
+        spyOn(ws);
         return ws;
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
index 86f0f8b..1c9eed2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
+import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
 
@@ -77,6 +78,20 @@
         }
     }
 
+    @Test
+    public void testEnableSizeCompatFreeform() {
+        try (SettingsSession enableSizeCompatFreeformSession = new
+                SettingsSession(DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM)) {
+            final boolean enableSizeCompatFreeform =
+                    !enableSizeCompatFreeformSession.getSetting();
+            final Uri enableSizeCompatFreeformUri =
+                    enableSizeCompatFreeformSession.setSetting(enableSizeCompatFreeform);
+            mWm.mSettingsObserver.onChange(false, enableSizeCompatFreeformUri);
+
+            assertEquals(mWm.mAtmService.mSizeCompatFreeform, enableSizeCompatFreeform);
+        }
+    }
+
     private class SettingsSession implements AutoCloseable {
 
         private static final int SETTING_VALUE_OFF = 0;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index 4fbf820..51daf65 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -33,16 +33,16 @@
  * A collection of static functions that provide access to WindowManager related test functionality.
  */
 class WindowTestUtils {
-    private static int sNextTaskId = 0;
 
     /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
-    static Task createTaskInStack(WindowManagerService service, TaskStack stack,
-            int userId) {
+    static Task createTaskInStack(WindowManagerService service, TaskStack stack, int userId) {
         synchronized (service.mGlobalLock) {
-            final Task newTask = new Task(sNextTaskId++, stack, userId, service, 0, false,
-                    new ActivityManager.TaskDescription(), null);
-            stack.addTask(newTask, POSITION_TOP);
-            return newTask;
+            final TaskRecord task = new ActivityTestsBase.TaskBuilder(
+                    stack.mActivityStack.mStackSupervisor)
+                    .setUserId(userId)
+                    .setStack(stack.mActivityStack)
+                    .build();
+            return task.mTask;
         }
     }
 
@@ -53,17 +53,33 @@
         return activity;
     }
 
+    static ActivityRecord createTestActivityRecord(ActivityStack stack) {
+        synchronized (stack.mService.mGlobalLock) {
+            final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(
+                    stack.mService)
+                    .setStack(stack)
+                    .setCreateTask(true)
+                    .build();
+            postCreateActivitySetup(activity, stack.mTaskStack.getDisplayContent());
+            return activity;
+        }
+    }
+
     static ActivityRecord createTestActivityRecord(DisplayContent dc) {
         synchronized (dc.mWmService.mGlobalLock) {
             final ActivityRecord activity = new ActivityBuilder(dc.mWmService.mAtmService).build();
-            activity.onDisplayChanged(dc);
-            activity.setOccludesParent(true);
-            activity.setHidden(false);
-            activity.hiddenRequested = false;
+            postCreateActivitySetup(activity, dc);
             return activity;
         }
     }
 
+    private static void postCreateActivitySetup(ActivityRecord activity, DisplayContent dc) {
+        activity.onDisplayChanged(dc);
+        activity.setOccludesParent(true);
+        activity.setHidden(false);
+        activity.hiddenRequested = false;
+    }
+
     static TestWindowToken createTestWindowToken(int type, DisplayContent dc) {
         return createTestWindowToken(type, dc, false /* persistOnEmpty */);
     }
@@ -92,49 +108,6 @@
         }
     }
 
-    /* Used so we can gain access to some protected members of the {@link Task} class */
-    static class TestTask extends Task {
-        boolean mShouldDeferRemoval = false;
-        boolean mOnDisplayChangedCalled = false;
-        private boolean mIsAnimating = false;
-
-        TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service,
-                int resizeMode, boolean supportsPictureInPicture,
-                TaskRecord taskRecord) {
-            super(taskId, stack, userId, service, resizeMode, supportsPictureInPicture,
-                    new ActivityManager.TaskDescription(), taskRecord);
-            stack.addTask(this, POSITION_TOP);
-        }
-
-        boolean shouldDeferRemoval() {
-            return mShouldDeferRemoval;
-        }
-
-        int positionInParent() {
-            return getParent().mChildren.indexOf(this);
-        }
-
-        @Override
-        void onDisplayChanged(DisplayContent dc) {
-            super.onDisplayChanged(dc);
-            mOnDisplayChangedCalled = true;
-        }
-
-        @Override
-        boolean isSelfAnimating() {
-            return mIsAnimating;
-        }
-
-        void setLocalIsAnimating(boolean isAnimating) {
-            mIsAnimating = isAnimating;
-        }
-    }
-
-    static TestTask createTestTask(TaskStack stack) {
-        return new TestTask(sNextTaskId++, stack, 0, stack.mWmService, RESIZE_MODE_UNRESIZEABLE,
-                false, mock(TaskRecord.class));
-    }
-
     /** Used to track resize reports. */
     static class TestWindowState extends WindowState {
         boolean mResizeReported;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index af9c510..780fed9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -211,11 +211,7 @@
     ActivityRecord createTestActivityRecord(DisplayContent dc, int
             windowingMode, int activityType) {
         final TaskStack stack = createTaskStackOnDisplay(windowingMode, activityType, dc);
-        final Task task = createTaskInStack(stack, 0 /* userId */);
-        final ActivityRecord activity =
-                WindowTestUtils.createTestActivityRecord(dc);
-        task.addChild(activity, 0);
-        return activity;
+        return WindowTestUtils.createTestActivityRecord(stack.mActivityStack);
     }
 
     WindowState createWindow(WindowState parent, int type, String name) {
@@ -327,14 +323,14 @@
 
     TaskStack createTaskStackOnDisplay(int windowingMode, int activityType, DisplayContent dc) {
         synchronized (mWm.mGlobalLock) {
-            final Configuration overrideConfig = new Configuration();
-            overrideConfig.windowConfiguration.setWindowingMode(windowingMode);
-            overrideConfig.windowConfiguration.setActivityType(activityType);
-            final int stackId = ++sNextStackId;
-            final TaskStack stack = new TaskStack(mWm, stackId, mock(ActivityStack.class));
-            dc.setStackOnDisplay(stackId, true, stack);
-            stack.onRequestedOverrideConfigurationChanged(overrideConfig);
-            return stack;
+            final ActivityStack stack = new ActivityTestsBase.StackBuilder(
+                    dc.mWmService.mAtmService.mRootActivityContainer)
+                    .setDisplay(dc.mActivityDisplay)
+                    .setWindowingMode(windowingMode)
+                    .setActivityType(activityType)
+                    .setCreateActivity(false)
+                    .build();
+            return stack.mTaskStack;
         }
     }
 
@@ -386,4 +382,9 @@
         displayInfo.ownerUid = SYSTEM_UID;
         return createNewDisplay(displayInfo);
     }
+
+    /** Sets the default minimum task size to 1 so that tests can use small task sizes */
+    public void removeGlobalMinSizeRestriction() {
+        mWm.mAtmService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp = 1;
+    }
 }
diff --git a/services/usage/java/com/android/server/usage/TEST_MAPPING b/services/usage/java/com/android/server/usage/TEST_MAPPING
new file mode 100644
index 0000000..7b53d09
--- /dev/null
+++ b/services/usage/java/com/android/server/usage/TEST_MAPPING
@@ -0,0 +1,33 @@
+{
+  "presubmit": [
+    {
+      "name": "FrameworksCoreTests",
+      "options": [
+        {
+          "include-filter": "android.app.usage"
+        }
+      ]
+    },
+    {
+      "name": "FrameworksServicesTests",
+      "options": [
+        {
+          "include-filter": "com.android.server.usage"
+        },
+        {
+          "exclude-filter": "com.android.server.usage.StorageStatsServiceTest"
+        }
+      ]
+    }
+  ],
+  "postsubmit": [
+    {
+      "name": "CtsUsageStatsTestCases",
+      "options": [
+        {
+          "include-filter": "android.app.usage.cts.UsageStatsTest"
+        }
+      ]
+    }
+  ]
+}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index db7ed1f..27d7360 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -373,7 +373,12 @@
                 Slog.e(TAG, "Failed read version upgrade breadcrumb");
                 throw new RuntimeException(e);
             }
-            continueUpgradeLocked(previousVersion, token);
+            if (mCurrentVersion >= 4) {
+                continueUpgradeLocked(previousVersion, token);
+            } else {
+                Slog.wtf(TAG, "Attempting to upgrade to an unsupported version: "
+                        + mCurrentVersion);
+            }
         }
 
         if (version != mCurrentVersion || mNewUpdate) {
@@ -487,6 +492,9 @@
     }
 
     private void continueUpgradeLocked(int version, long token) {
+        if (version <= 3) {
+            Slog.w(TAG, "Reading UsageStats as XML; current database version: " + mCurrentVersion);
+        }
         final File backupDir = new File(mBackupsDir, Long.toString(token));
 
         // Upgrade step logic for the entire usage stats directory, not individual interval dirs.
@@ -876,6 +884,10 @@
     }
 
     private void writeLocked(AtomicFile file, IntervalStats stats) throws IOException {
+        if (mCurrentVersion <= 3) {
+            Slog.wtf(TAG, "Attempting to write UsageStats as XML with version " + mCurrentVersion);
+            return;
+        }
         writeLocked(file, stats, mCurrentVersion, mPackagesTokenData);
     }
 
@@ -892,17 +904,13 @@
         }
     }
 
-    private void writeLocked(OutputStream out, IntervalStats stats) throws IOException {
-        writeLocked(out, stats, mCurrentVersion, mPackagesTokenData);
-    }
-
     private static void writeLocked(OutputStream out, IntervalStats stats, int version,
             PackagesTokenData packagesTokenData) throws IOException {
         switch (version) {
             case 1:
             case 2:
             case 3:
-                UsageStatsXml.write(out, stats);
+                Slog.wtf(TAG, "Attempting to write UsageStats as XML with version " + version);
                 break;
             case 4:
                 try {
@@ -927,6 +935,10 @@
     }
 
     private void readLocked(AtomicFile file, IntervalStats statsOut) throws IOException {
+        if (mCurrentVersion <= 3) {
+            Slog.wtf(TAG, "Reading UsageStats as XML; current database version: "
+                    + mCurrentVersion);
+        }
         readLocked(file, statsOut, mCurrentVersion, mPackagesTokenData);
     }
 
@@ -951,17 +963,18 @@
         }
     }
 
-    private void readLocked(InputStream in, IntervalStats statsOut) throws IOException {
-        readLocked(in, statsOut, mCurrentVersion, mPackagesTokenData);
-    }
-
     private static void readLocked(InputStream in, IntervalStats statsOut, int version,
             PackagesTokenData packagesTokenData) throws IOException {
         switch (version) {
             case 1:
             case 2:
             case 3:
-                UsageStatsXml.read(in, statsOut);
+                Slog.w(TAG, "Reading UsageStats as XML; database version: " + version);
+                try {
+                    UsageStatsXml.read(in, statsOut);
+                } catch (Exception e) {
+                    Slog.e(TAG, "Unable to read interval stats from XML", e);
+                }
                 break;
             case 4:
                 try {
@@ -1076,6 +1089,10 @@
      */
     @VisibleForTesting
     public byte[] getBackupPayload(String key, int version) {
+        if (version >= 1 && version <= 3) {
+            Slog.wtf(TAG, "Attempting to backup UsageStats as XML with version " + version);
+            return null;
+        }
         synchronized (mLock) {
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
             if (KEY_USAGE_STATS.equals(key)) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsProto.java b/services/usage/java/com/android/server/usage/UsageStatsProto.java
index 5d1f730..87e077e 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsProto.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsProto.java
@@ -334,8 +334,6 @@
             proto.write(IntervalStatsProto.UsageStats.PACKAGE_INDEX, packageIndex + 1);
         } else {
             // Package not in Stringpool for some reason, write full string instead
-            Slog.w(TAG, "UsageStats package name (" + usageStats.mPackageName
-                    + ") not found in IntervalStats string cache");
             proto.write(IntervalStatsProto.UsageStats.PACKAGE, usageStats.mPackageName);
         }
         // Time attributes stored as an offset of the beginTime.
@@ -430,8 +428,6 @@
             proto.write(IntervalStatsProto.Event.PACKAGE_INDEX, packageIndex + 1);
         } else {
             // Package not in Stringpool for some reason, write full string instead
-            Slog.w(TAG, "Usage event package name (" + event.mPackage
-                    + ") not found in IntervalStats string cache");
             proto.write(IntervalStatsProto.Event.PACKAGE, event.mPackage);
         }
         if (event.mClass != null) {
@@ -440,8 +436,6 @@
                 proto.write(IntervalStatsProto.Event.CLASS_INDEX, classIndex + 1);
             } else {
                 // Class not in Stringpool for some reason, write full string instead
-                Slog.w(TAG, "Usage event class name (" + event.mClass
-                        + ") not found in IntervalStats string cache");
                 proto.write(IntervalStatsProto.Event.CLASS, event.mClass);
             }
         }
@@ -454,10 +448,6 @@
             if (taskRootPackageIndex >= 0) {
                 proto.write(IntervalStatsProto.Event.TASK_ROOT_PACKAGE_INDEX,
                         taskRootPackageIndex + 1);
-            } else {
-                // Task root package not in Stringpool for some reason.
-                Slog.w(TAG, "Usage event task root package name (" + event.mTaskRootPackage
-                        + ") not found in IntervalStats string cache");
             }
         }
         if (event.mTaskRootClass != null) {
@@ -465,10 +455,6 @@
             if (taskRootClassIndex >= 0) {
                 proto.write(IntervalStatsProto.Event.TASK_ROOT_CLASS_INDEX,
                         taskRootClassIndex + 1);
-            } else {
-                // Task root class not in Stringpool for some reason.
-                Slog.w(TAG, "Usage event task root class name (" + event.mTaskRootClass
-                        + ") not found in IntervalStats string cache");
             }
         }
         switch (event.mEventType) {
@@ -496,9 +482,6 @@
                                 channelIndex + 1);
                     } else {
                         // Channel not in Stringpool for some reason, write full string instead
-                        Slog.w(TAG, "Usage event notification channel name ("
-                                + event.mNotificationChannelId
-                                + ") not found in IntervalStats string cache");
                         proto.write(IntervalStatsProto.Event.NOTIFICATION_CHANNEL,
                                 event.mNotificationChannelId);
                     }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java b/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java
index 7d8e430..b68e04f 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java
@@ -448,10 +448,10 @@
                         final long packagesToken = proto.start(
                                 IntervalStatsObfuscatedProto.PACKAGES);
                         UsageStats usageStats = parseUsageStats(proto, stats.beginTime);
+                        proto.end(packagesToken);
                         if (usageStats.mPackageToken != PackagesTokenData.UNASSIGNED_TOKEN) {
                             stats.packageStatsObfuscated.put(usageStats.mPackageToken, usageStats);
                         }
-                        proto.end(packagesToken);
                     } catch (IOException e) {
                         Slog.e(TAG, "Unable to read some usage stats from proto.", e);
                     }
@@ -484,6 +484,13 @@
                     if (stats.endTime == 0) {
                         stats.endTime = stats.beginTime;
                     }
+                    // update the begin and end time stamps for all usage stats
+                    final int usageStatsSize = stats.packageStatsObfuscated.size();
+                    for (int i = 0; i < usageStatsSize; i++) {
+                        final UsageStats usageStats = stats.packageStatsObfuscated.valueAt(i);
+                        usageStats.mBeginTimeStamp = stats.beginTime;
+                        usageStats.mEndTimeStamp = stats.endTime;
+                    }
                     return;
             }
         }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 5d03e151..f9b3659 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -86,6 +86,7 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
 
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
@@ -180,8 +181,8 @@
         }
     }
 
-    private UsageStatsManagerInternal.AppIdleStateChangeListener mStandbyChangeListener =
-            new UsageStatsManagerInternal.AppIdleStateChangeListener() {
+    private AppIdleStateChangeListener mStandbyChangeListener =
+            new AppIdleStateChangeListener() {
                 @Override
                 public void onAppIdleStateChanged(String packageName, int userId, boolean idle,
                         int bucket, int reason) {
@@ -253,6 +254,7 @@
                 null, mHandler);
 
         publishLocalService(UsageStatsManagerInternal.class, new LocalService());
+        publishLocalService(AppStandbyInternal.class, mAppStandby);
         publishBinderService(Context.USAGE_STATS_SERVICE, new BinderService());
     }
 
@@ -398,7 +400,7 @@
 
     private final IUidObserver mUidObserver = new IUidObserver.Stub() {
         @Override
-        public void onUidStateChanged(int uid, int procState, long procStateSeq) {
+        public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) {
             mHandler.obtainMessage(MSG_UID_STATE_CHANGED, uid, procState).sendToTarget();
         }
 
@@ -409,7 +411,8 @@
 
         @Override
         public void onUidGone(int uid, boolean disabled) {
-            onUidStateChanged(uid, ActivityManager.PROCESS_STATE_NONEXISTENT, 0);
+            onUidStateChanged(uid, ActivityManager.PROCESS_STATE_NONEXISTENT, 0,
+                    ActivityManager.PROCESS_CAPABILITY_NONE);
         }
 
         @Override
@@ -2029,17 +2032,6 @@
         }
 
         @Override
-        public void addAppIdleStateChangeListener(AppIdleStateChangeListener listener) {
-            mAppStandby.addListener(listener);
-        }
-
-        @Override
-        public void removeAppIdleStateChangeListener(
-                AppIdleStateChangeListener listener) {
-            mAppStandby.removeListener(listener);
-        }
-
-        @Override
         public byte[] getBackupPayload(int user, String key) {
             synchronized (mLock) {
                 if (!mUserUnlockedStates.get(user)) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsXml.java b/services/usage/java/com/android/server/usage/UsageStatsXml.java
index f8d1113..3100310 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXml.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXml.java
@@ -16,14 +16,11 @@
 
 package com.android.server.usage;
 
-import android.util.AtomicFile;
 import android.util.Slog;
 import android.util.Xml;
-import android.util.proto.ProtoInputStream;
-import android.util.proto.ProtoOutputStream;
 
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -31,7 +28,6 @@
 
 public class UsageStatsXml {
     private static final String TAG = "UsageStatsXml";
-    private static final int CURRENT_VERSION = 1;
     private static final String USAGESTATS_TAG = "usagestats";
     private static final String VERSION_ATTR = "version";
     static final String CHECKED_IN_SUFFIX = "-c";
@@ -61,18 +57,4 @@
             throw new IOException(e);
         }
     }
-
-    public static void write(OutputStream out, IntervalStats stats) throws IOException {
-        FastXmlSerializer xml = new FastXmlSerializer();
-        xml.setOutput(out, "utf-8");
-        xml.startDocument("utf-8", true);
-        xml.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-        xml.startTag(null, USAGESTATS_TAG);
-        xml.attribute(null, VERSION_ATTR, Integer.toString(CURRENT_VERSION));
-
-        UsageStatsXmlV1.write(xml, stats);
-
-        xml.endTag(null, USAGESTATS_TAG);
-        xml.endDocument();
-    }
 }
\ No newline at end of file
diff --git a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
index 565ca9e..2598739 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
@@ -26,7 +26,6 @@
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 import java.net.ProtocolException;
@@ -243,135 +242,6 @@
         statsOut.addEvent(event);
     }
 
-    private static void writeUsageStats(XmlSerializer xml, final IntervalStats stats,
-            final UsageStats usageStats) throws IOException {
-        xml.startTag(null, PACKAGE_TAG);
-
-        // Write the time offset.
-        XmlUtils.writeLongAttribute(xml, LAST_TIME_ACTIVE_ATTR,
-                usageStats.mLastTimeUsed - stats.beginTime);
-        XmlUtils.writeLongAttribute(xml, LAST_TIME_VISIBLE_ATTR,
-                usageStats.mLastTimeVisible - stats.beginTime);
-        XmlUtils.writeLongAttribute(xml, LAST_TIME_SERVICE_USED_ATTR,
-                usageStats.mLastTimeForegroundServiceUsed - stats.beginTime);
-        XmlUtils.writeStringAttribute(xml, PACKAGE_ATTR, usageStats.mPackageName);
-        XmlUtils.writeLongAttribute(xml, TOTAL_TIME_ACTIVE_ATTR, usageStats.mTotalTimeInForeground);
-        XmlUtils.writeLongAttribute(xml, TOTAL_TIME_VISIBLE_ATTR, usageStats.mTotalTimeVisible);
-        XmlUtils.writeLongAttribute(xml, TOTAL_TIME_SERVICE_USED_ATTR,
-                usageStats.mTotalTimeForegroundServiceUsed);
-        XmlUtils.writeIntAttribute(xml, LAST_EVENT_ATTR, usageStats.mLastEvent);
-        if (usageStats.mAppLaunchCount > 0) {
-            XmlUtils.writeIntAttribute(xml, APP_LAUNCH_COUNT_ATTR, usageStats.mAppLaunchCount);
-        }
-        writeChooserCounts(xml, usageStats);
-        xml.endTag(null, PACKAGE_TAG);
-    }
-
-    private static void writeCountAndTime(XmlSerializer xml, String tag, int count, long time)
-            throws IOException {
-        xml.startTag(null, tag);
-        XmlUtils.writeIntAttribute(xml, COUNT_ATTR, count);
-        XmlUtils.writeLongAttribute(xml, TIME_ATTR, time);
-        xml.endTag(null, tag);
-    }
-
-    private static void writeChooserCounts(XmlSerializer xml, final UsageStats usageStats)
-            throws IOException {
-        if (usageStats == null || usageStats.mChooserCounts == null ||
-                usageStats.mChooserCounts.keySet().isEmpty()) {
-            return;
-        }
-        final int chooserCountSize = usageStats.mChooserCounts.size();
-        for (int i = 0; i < chooserCountSize; i++) {
-            final String action = usageStats.mChooserCounts.keyAt(i);
-            final ArrayMap<String, Integer> counts = usageStats.mChooserCounts.valueAt(i);
-            if (action == null || counts == null || counts.isEmpty()) {
-                continue;
-            }
-            xml.startTag(null, CHOOSER_COUNT_TAG);
-            XmlUtils.writeStringAttribute(xml, NAME, action);
-            writeCountsForAction(xml, counts);
-            xml.endTag(null, CHOOSER_COUNT_TAG);
-        }
-    }
-
-    private static void writeCountsForAction(XmlSerializer xml, ArrayMap<String, Integer> counts)
-            throws IOException {
-        final int countsSize = counts.size();
-        for (int i = 0; i < countsSize; i++) {
-            String key = counts.keyAt(i);
-            int count = counts.valueAt(i);
-            if (count > 0) {
-                xml.startTag(null, CATEGORY_TAG);
-                XmlUtils.writeStringAttribute(xml, NAME, key);
-                XmlUtils.writeIntAttribute(xml, COUNT, count);
-                xml.endTag(null, CATEGORY_TAG);
-            }
-        }
-    }
-
-    private static void writeConfigStats(XmlSerializer xml, final IntervalStats stats,
-            final ConfigurationStats configStats, boolean isActive) throws IOException {
-        xml.startTag(null, CONFIG_TAG);
-
-        // Write the time offset.
-        XmlUtils.writeLongAttribute(xml, LAST_TIME_ACTIVE_ATTR,
-                configStats.mLastTimeActive - stats.beginTime);
-
-        XmlUtils.writeLongAttribute(xml, TOTAL_TIME_ACTIVE_ATTR, configStats.mTotalTimeActive);
-        XmlUtils.writeIntAttribute(xml, COUNT_ATTR, configStats.mActivationCount);
-        if (isActive) {
-            XmlUtils.writeBooleanAttribute(xml, ACTIVE_ATTR, true);
-        }
-
-        // Now write the attributes representing the configuration object.
-        Configuration.writeXmlAttrs(xml, configStats.mConfiguration);
-
-        xml.endTag(null, CONFIG_TAG);
-    }
-
-    private static void writeEvent(XmlSerializer xml, final IntervalStats stats,
-            final UsageEvents.Event event) throws IOException {
-        xml.startTag(null, EVENT_TAG);
-
-        // Store the time offset.
-        XmlUtils.writeLongAttribute(xml, TIME_ATTR, event.mTimeStamp - stats.beginTime);
-
-        XmlUtils.writeStringAttribute(xml, PACKAGE_ATTR, event.mPackage);
-        if (event.mClass != null) {
-            XmlUtils.writeStringAttribute(xml, CLASS_ATTR, event.mClass);
-        }
-        XmlUtils.writeIntAttribute(xml, FLAGS_ATTR, event.mFlags);
-        XmlUtils.writeIntAttribute(xml, TYPE_ATTR, event.mEventType);
-        XmlUtils.writeIntAttribute(xml, INSTANCE_ID_ATTR, event.mInstanceId);
-
-        switch (event.mEventType) {
-            case UsageEvents.Event.CONFIGURATION_CHANGE:
-                if (event.mConfiguration != null) {
-                    Configuration.writeXmlAttrs(xml, event.mConfiguration);
-                }
-                break;
-            case UsageEvents.Event.SHORTCUT_INVOCATION:
-                if (event.mShortcutId != null) {
-                    XmlUtils.writeStringAttribute(xml, SHORTCUT_ID_ATTR, event.mShortcutId);
-                }
-                break;
-            case UsageEvents.Event.STANDBY_BUCKET_CHANGED:
-                if (event.mBucketAndReason != 0) {
-                    XmlUtils.writeIntAttribute(xml, STANDBY_BUCKET_ATTR, event.mBucketAndReason);
-                }
-                break;
-            case UsageEvents.Event.NOTIFICATION_INTERRUPTION:
-                if (event.mNotificationChannelId != null) {
-                    XmlUtils.writeStringAttribute(
-                            xml, NOTIFICATION_CHANNEL_ATTR, event.mNotificationChannelId);
-                }
-                break;
-        }
-
-        xml.endTag(null, EVENT_TAG);
-    }
-
     /**
      * Reads from the {@link XmlPullParser}, assuming that it is already on the
      * <code><usagestats></code> tag.
@@ -440,51 +310,6 @@
         }
     }
 
-    /**
-     * Writes the stats object to an XML file. The {@link XmlSerializer}
-     * has already written the <code><usagestats></code> tag, but attributes may still
-     * be added.
-     *
-     * @param xml The serializer to which to write the packageStats data.
-     * @param stats The stats object to write to the XML file.
-     */
-    public static void write(XmlSerializer xml, IntervalStats stats) throws IOException {
-        XmlUtils.writeLongAttribute(xml, END_TIME_ATTR, stats.endTime - stats.beginTime);
-        XmlUtils.writeIntAttribute(xml, MAJOR_VERSION_ATTR, stats.majorVersion);
-        XmlUtils.writeIntAttribute(xml, MINOR_VERSION_ATTR, stats.minorVersion);
-
-        writeCountAndTime(xml, INTERACTIVE_TAG, stats.interactiveTracker.count,
-                stats.interactiveTracker.duration);
-        writeCountAndTime(xml, NON_INTERACTIVE_TAG, stats.nonInteractiveTracker.count,
-                stats.nonInteractiveTracker.duration);
-        writeCountAndTime(xml, KEYGUARD_SHOWN_TAG, stats.keyguardShownTracker.count,
-                stats.keyguardShownTracker.duration);
-        writeCountAndTime(xml, KEYGUARD_HIDDEN_TAG, stats.keyguardHiddenTracker.count,
-                stats.keyguardHiddenTracker.duration);
-
-        xml.startTag(null, PACKAGES_TAG);
-        final int statsCount = stats.packageStats.size();
-        for (int i = 0; i < statsCount; i++) {
-            writeUsageStats(xml, stats, stats.packageStats.valueAt(i));
-        }
-        xml.endTag(null, PACKAGES_TAG);
-
-        xml.startTag(null, CONFIGURATIONS_TAG);
-        final int configCount = stats.configurations.size();
-        for (int i = 0; i < configCount; i++) {
-            boolean active = stats.activeConfiguration.equals(stats.configurations.keyAt(i));
-            writeConfigStats(xml, stats, stats.configurations.valueAt(i), active);
-        }
-        xml.endTag(null, CONFIGURATIONS_TAG);
-
-        xml.startTag(null, EVENT_LOG_TAG);
-        final int eventCount = stats.events.size();
-        for (int i = 0; i < eventCount; i++) {
-            writeEvent(xml, stats, stats.events.get(i));
-        }
-        xml.endTag(null, EVENT_LOG_TAG);
-    }
-
     private UsageStatsXmlV1() {
     }
 }
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 23df1c5..5783932 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -146,17 +146,16 @@
         }
 
         // During system reboot, add a DEVICE_SHUTDOWN event to the end of event list, the timestamp
-        // is last time UsageStatsDatabase is persisted to disk.
+        // is last time UsageStatsDatabase is persisted to disk or the last event's time whichever
+        // is higher (because the file system timestamp is round down to integral seconds).
         // Also add a DEVICE_STARTUP event with current system timestamp.
         final IntervalStats currentDailyStats = mCurrentStats[INTERVAL_DAILY];
         if (currentDailyStats != null) {
-            // File system timestamp only has precision of 1 second, add 1000ms to make up
-            // for the loss of round up.
-            final Event shutdownEvent =
-                    new Event(DEVICE_SHUTDOWN, currentDailyStats.lastTimeSaved + 1000);
+            final Event shutdownEvent = new Event(DEVICE_SHUTDOWN,
+                    Math.max(currentDailyStats.lastTimeSaved, currentDailyStats.endTime));
             shutdownEvent.mPackage = Event.DEVICE_EVENT_PACKAGE_NAME;
             currentDailyStats.addEvent(shutdownEvent);
-            final Event startupEvent = new Event(DEVICE_STARTUP, currentTimeMillis);
+            final Event startupEvent = new Event(DEVICE_STARTUP, System.currentTimeMillis());
             startupEvent.mPackage = Event.DEVICE_EVENT_PACKAGE_NAME;
             currentDailyStats.addEvent(startupEvent);
         }
diff --git a/services/usb/java/com/android/server/usb/UsbPermissionManager.java b/services/usb/java/com/android/server/usb/UsbPermissionManager.java
index ef9ee73..1e46f98 100644
--- a/services/usb/java/com/android/server/usb/UsbPermissionManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPermissionManager.java
@@ -20,14 +20,20 @@
 import android.annotation.UserIdInt;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.UserInfo;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbManager;
 import android.os.UserHandle;
+import android.os.UserManager;
+import android.service.usb.UsbSettingsManagerProto;
 import android.util.Slog;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.dump.DualDumpOutputStream;
+
+import java.util.List;
 
 class UsbPermissionManager {
     private static final String LOG_TAG = UsbPermissionManager.class.getSimpleName();
@@ -112,4 +118,18 @@
         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
     }
 
+    void dump(@NonNull DualDumpOutputStream dump, String idName, long id) {
+        long token = dump.start(idName, id);
+        UserManager userManager = mContext.getSystemService(UserManager.class);
+        synchronized (mPermissionsByUser) {
+            List<UserInfo> users = userManager.getUsers();
+            int numUsers = users.size();
+            for (int i = 0; i < numUsers; i++) {
+                getPermissionsForUser(users.get(i).id).dump(dump, "user_permissions",
+                        UsbSettingsManagerProto.USER_SETTINGS);
+            }
+        }
+        dump.end(token);
+    }
+
 }
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index ce6f592..0493637 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -740,6 +740,8 @@
 
                 mSettingsManager.dump(dump, "settings_manager",
                         UsbServiceDumpProto.SETTINGS_MANAGER);
+                mPermissionManager.dump(dump, "permissions_manager",
+                        UsbServiceDumpProto.PERMISSIONS_MANAGER);
                 dump.flush();
             } else if ("set-port-roles".equals(args[0]) && args.length == 4) {
                 final String portId = args[1];
diff --git a/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java b/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
index 0cb64a3..e700f19 100644
--- a/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
+++ b/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
@@ -36,9 +36,12 @@
 import android.os.Environment;
 import android.os.Process;
 import android.os.UserHandle;
-import android.service.usb.UsbSettingsAccessoryPermissionProto;
-import android.service.usb.UsbSettingsDevicePermissionProto;
-import android.service.usb.UsbUserSettingsManagerProto;
+import android.service.usb.UsbAccessoryPermissionProto;
+import android.service.usb.UsbAccessoryPersistentPermissionProto;
+import android.service.usb.UsbDevicePermissionProto;
+import android.service.usb.UsbDevicePersistentPermissionProto;
+import android.service.usb.UsbUidPermissionProto;
+import android.service.usb.UsbUserPermissionsManagerProto;
 import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.Slog;
@@ -261,7 +264,7 @@
             }
 
             if (isChanged) {
-                scheduleWritePermissionLocked();
+                scheduleWritePermissionsLocked();
             }
         }
     }
@@ -288,7 +291,7 @@
             }
 
             if (isChanged) {
-                scheduleWritePermissionLocked();
+                scheduleWritePermissionsLocked();
             }
         }
     }
@@ -370,7 +373,7 @@
     }
 
     @GuardedBy("mLock")
-    private void scheduleWritePermissionLocked() {
+    private void scheduleWritePermissionsLocked() {
         if (mIsCopyPermissionsScheduled) {
             return;
         }
@@ -393,15 +396,18 @@
                 devices = new DeviceFilter[numDevices];
                 uidsForDevices = new int[numDevices][];
                 grantedValuesForDevices = new boolean[numDevices][];
-                for (int i = 0; i < numDevices; i++) {
-                    devices[i] = new DeviceFilter(mDevicePersistentPermissionMap.keyAt(i));
-                    SparseBooleanArray permissions = mDevicePersistentPermissionMap.valueAt(i);
+                for (int deviceIdx = 0; deviceIdx < numDevices; deviceIdx++) {
+                    devices[deviceIdx] =
+                            new DeviceFilter(mDevicePersistentPermissionMap.keyAt(deviceIdx));
+                    SparseBooleanArray permissions =
+                            mDevicePersistentPermissionMap.valueAt(deviceIdx);
                     int numPermissions = permissions.size();
-                    uidsForDevices[i] = new int[numPermissions];
-                    grantedValuesForDevices[i] = new boolean[numPermissions];
-                    for (int j = 0; j < numPermissions; j++) {
-                        uidsForDevices[i][j] = permissions.keyAt(j);
-                        grantedValuesForDevices[i][j] = permissions.valueAt(j);
+                    uidsForDevices[deviceIdx] = new int[numPermissions];
+                    grantedValuesForDevices[deviceIdx] = new boolean[numPermissions];
+                    for (int permissionIdx = 0; permissionIdx < numPermissions; permissionIdx++) {
+                        uidsForDevices[deviceIdx][permissionIdx] = permissions.keyAt(permissionIdx);
+                        grantedValuesForDevices[deviceIdx][permissionIdx] =
+                                permissions.valueAt(permissionIdx);
                     }
                 }
 
@@ -409,16 +415,19 @@
                 accessories = new AccessoryFilter[numAccessories];
                 uidsForAccessories = new int[numAccessories][];
                 grantedValuesForAccessories = new boolean[numAccessories][];
-                for (int i = 0; i < numAccessories; i++) {
-                    accessories[i] =
-                            new AccessoryFilter(mAccessoryPersistentPermissionMap.keyAt(i));
-                    SparseBooleanArray permissions = mAccessoryPersistentPermissionMap.valueAt(i);
+                for (int accessoryIdx = 0; accessoryIdx < numAccessories; accessoryIdx++) {
+                    accessories[accessoryIdx] = new AccessoryFilter(
+                                    mAccessoryPersistentPermissionMap.keyAt(accessoryIdx));
+                    SparseBooleanArray permissions =
+                            mAccessoryPersistentPermissionMap.valueAt(accessoryIdx);
                     int numPermissions = permissions.size();
-                    uidsForAccessories[i] = new int[numPermissions];
-                    grantedValuesForAccessories[i] = new boolean[numPermissions];
-                    for (int j = 0; j < numPermissions; j++) {
-                        uidsForAccessories[i][j] = permissions.keyAt(j);
-                        grantedValuesForAccessories[i][j] = permissions.valueAt(j);
+                    uidsForAccessories[accessoryIdx] = new int[numPermissions];
+                    grantedValuesForAccessories[accessoryIdx] = new boolean[numPermissions];
+                    for (int permissionIdx = 0; permissionIdx < numPermissions; permissionIdx++) {
+                        uidsForAccessories[accessoryIdx][permissionIdx] =
+                                permissions.keyAt(permissionIdx);
+                        grantedValuesForAccessories[accessoryIdx][permissionIdx] =
+                                permissions.valueAt(permissionIdx);
                     }
                 }
                 mIsCopyPermissionsScheduled = false;
@@ -477,22 +486,22 @@
      * Creates UI dialog to request permission for the given package to access the device
      * or accessory.
      *
-     * @param device The USB device attached
-     * @param accessory The USB accessory attached
+     * @param device       The USB device attached
+     * @param accessory    The USB accessory attached
      * @param canBeDefault Whether the calling pacakge can set as default handler
-     * of the USB device or accessory
-     * @param packageName The package name of the calling package
-     * @param uid The uid of the calling package
-     * @param userContext The context to start the UI dialog
-     * @param pi PendingIntent for returning result
+     *                     of the USB device or accessory
+     * @param packageName  The package name of the calling package
+     * @param uid          The uid of the calling package
+     * @param userContext  The context to start the UI dialog
+     * @param pi           PendingIntent for returning result
      */
     void requestPermissionDialog(@Nullable UsbDevice device,
-                                 @Nullable UsbAccessory accessory,
-                                 boolean canBeDefault,
-                                 @NonNull String packageName,
-                                 int uid,
-                                 @NonNull Context userContext,
-                                 @NonNull PendingIntent pi) {
+            @Nullable UsbAccessory accessory,
+            boolean canBeDefault,
+            @NonNull String packageName,
+            int uid,
+            @NonNull Context userContext,
+            @NonNull PendingIntent pi) {
         long identity = Binder.clearCallingIdentity();
         Intent intent = new Intent();
         if (device != null) {
@@ -517,48 +526,96 @@
         }
     }
 
-    void dump(@NonNull DualDumpOutputStream dump) {
+    void dump(@NonNull DualDumpOutputStream dump, String idName, long id) {
+        long token = dump.start(idName, id);
         synchronized (mLock) {
-            for (String deviceName : mDevicePermissionMap.keySet()) {
+            dump.write("user_id", UsbUserPermissionsManagerProto.USER_ID, mUser.getIdentifier());
+            int numMappings = mDevicePermissionMap.size();
+            for (int mappingsIdx = 0; mappingsIdx < numMappings; mappingsIdx++) {
+                String deviceName = mDevicePermissionMap.keyAt(mappingsIdx);
                 long devicePermissionToken = dump.start("device_permissions",
-                        UsbUserSettingsManagerProto.DEVICE_PERMISSIONS);
+                        UsbUserPermissionsManagerProto.DEVICE_PERMISSIONS);
 
-                dump.write("device_name", UsbSettingsDevicePermissionProto.DEVICE_NAME, deviceName);
+                dump.write("device_name", UsbDevicePermissionProto.DEVICE_NAME, deviceName);
 
-                SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName);
-                int count = uidList.size();
-                for (int i = 0; i < count; i++) {
-                    dump.write("uids", UsbSettingsDevicePermissionProto.UIDS, uidList.keyAt(i));
+                SparseBooleanArray uidList = mDevicePermissionMap.valueAt(mappingsIdx);
+                int numUids = uidList.size();
+                for (int uidsIdx = 0; uidsIdx < numUids; uidsIdx++) {
+                    dump.write("uids", UsbDevicePermissionProto.UIDS, uidList.keyAt(uidsIdx));
                 }
 
                 dump.end(devicePermissionToken);
             }
 
-            for (UsbAccessory accessory : mAccessoryPermissionMap.keySet()) {
+            numMappings = mAccessoryPermissionMap.size();
+            for (int mappingsIdx = 0; mappingsIdx < numMappings; ++mappingsIdx) {
+                UsbAccessory accessory = mAccessoryPermissionMap.keyAt(mappingsIdx);
                 long accessoryPermissionToken = dump.start("accessory_permissions",
-                        UsbUserSettingsManagerProto.ACCESSORY_PERMISSIONS);
+                        UsbUserPermissionsManagerProto.ACCESSORY_PERMISSIONS);
 
                 dump.write("accessory_description",
-                        UsbSettingsAccessoryPermissionProto.ACCESSORY_DESCRIPTION,
+                        UsbAccessoryPermissionProto.ACCESSORY_DESCRIPTION,
                         accessory.getDescription());
 
-                SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
-                int count = uidList.size();
-                for (int i = 0; i < count; i++) {
-                    dump.write("uids", UsbSettingsAccessoryPermissionProto.UIDS, uidList.keyAt(i));
+                SparseBooleanArray uidList = mAccessoryPermissionMap.valueAt(mappingsIdx);
+                int numUids = uidList.size();
+                for (int uidsIdx = 0; uidsIdx < numUids; uidsIdx++) {
+                    dump.write("uids", UsbAccessoryPermissionProto.UIDS, uidList.keyAt(uidsIdx));
                 }
 
                 dump.end(accessoryPermissionToken);
             }
+
+            numMappings = mDevicePersistentPermissionMap.size();
+            for (int mappingsIdx = 0; mappingsIdx < numMappings; mappingsIdx++) {
+                DeviceFilter filter = mDevicePersistentPermissionMap.keyAt(mappingsIdx);
+                long devicePermissionToken = dump.start("device_persistent_permissions",
+                        UsbUserPermissionsManagerProto.DEVICE_PERSISTENT_PERMISSIONS);
+                filter.dump(dump, "device",
+                        UsbDevicePersistentPermissionProto.DEVICE_FILTER);
+                SparseBooleanArray permissions =
+                        mDevicePersistentPermissionMap.valueAt(mappingsIdx);
+                int numPermissions = permissions.size();
+                for (int permissionsIdx = 0; permissionsIdx < numPermissions; permissionsIdx++) {
+                    long uidPermissionToken = dump.start("uid_permission",
+                            UsbDevicePersistentPermissionProto.PERMISSION_VALUES);
+                    dump.write("uid", UsbUidPermissionProto.UID, permissions.keyAt(permissionsIdx));
+                    dump.write("is_granted",
+                            UsbUidPermissionProto.IS_GRANTED, permissions.valueAt(permissionsIdx));
+                    dump.end(uidPermissionToken);
+                }
+                dump.end(devicePermissionToken);
+            }
+
+            numMappings = mAccessoryPersistentPermissionMap.size();
+            for (int mappingsIdx = 0; mappingsIdx < numMappings; mappingsIdx++) {
+                AccessoryFilter filter = mAccessoryPersistentPermissionMap.keyAt(mappingsIdx);
+                long accessoryPermissionToken = dump.start("accessory_persistent_permissions",
+                        UsbUserPermissionsManagerProto.ACCESSORY_PERSISTENT_PERMISSIONS);
+                filter.dump(dump, "accessory",
+                        UsbAccessoryPersistentPermissionProto.ACCESSORY_FILTER);
+                SparseBooleanArray permissions =
+                        mAccessoryPersistentPermissionMap.valueAt(mappingsIdx);
+                int numPermissions = permissions.size();
+                for (int permissionsIdx = 0; permissionsIdx < numPermissions; permissionsIdx++) {
+                    long uidPermissionToken = dump.start("uid_permission",
+                            UsbAccessoryPersistentPermissionProto.PERMISSION_VALUES);
+                    dump.write("uid", UsbUidPermissionProto.UID, permissions.keyAt(permissionsIdx));
+                    dump.write("is_granted",
+                            UsbUidPermissionProto.IS_GRANTED, permissions.valueAt(permissionsIdx));
+                    dump.end(uidPermissionToken);
+                }
+                dump.end(accessoryPermissionToken);
+            }
         }
+        dump.end(token);
     }
 
     /**
      * Check for camera permission of the calling process.
      *
      * @param packageName Package name of the caller.
-     * @param uid Linux uid of the calling process.
-     *
+     * @param uid         Linux uid of the calling process.
      * @return True in case camera permission is available, False otherwise.
      */
     private boolean isCameraPermissionGranted(String packageName, int uid) {
@@ -677,7 +734,7 @@
      *
      * @param device The device that needs to get scanned
      * @return True in case a VIDEO device or interface is present,
-     *         False otherwise.
+     * False otherwise.
      */
     private boolean isCameraDevicePresent(UsbDevice device) {
         if (device.getDeviceClass() == UsbConstants.USB_CLASS_VIDEO) {
diff --git a/startop/apps/test/Android.bp b/startop/apps/test/Android.bp
index 2ff26b8..3f20273 100644
--- a/startop/apps/test/Android.bp
+++ b/startop/apps/test/Android.bp
@@ -18,9 +18,12 @@
     name: "startop_test_app",
     srcs: [
         "src/ComplexLayoutInflationActivity.java",
-        "src/CPUIntensive.java",
+        "src/CPUIntensiveBenchmarkActivity.java",
+        "src/CPUIntensiveBenchmarks.java",
         "src/EmptyActivity.java",
         "src/FrameLayoutInflationActivity.java",
+        "src/InitCheckOverheadBenchmarkActivity.java",
+        "src/InitCheckOverheadBenchmarks.java",
         "src/LayoutInflationActivity.java",
         "src/NonInteractiveSystemServerBenchmarkActivity.java",
         "src/SystemServerBenchmarkActivity.java",
diff --git a/startop/apps/test/AndroidManifest.xml b/startop/apps/test/AndroidManifest.xml
index ebe2584..235aa0d 100644
--- a/startop/apps/test/AndroidManifest.xml
+++ b/startop/apps/test/AndroidManifest.xml
@@ -37,6 +37,18 @@
         </activity>
 
         <activity
+            android:label="CPU Intensive Benchmark Test"
+            android:name=".CPUIntensiveBenchmarkActivity"
+            android:exported="true" >
+
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity
             android:label="Empty Activity Layout Test"
             android:name=".EmptyActivity"
             android:exported="true" >
@@ -61,6 +73,18 @@
         </activity>
 
         <activity
+            android:label="Initialization Check Overhead Test"
+            android:name=".InitCheckOverheadBenchmarkActivity"
+            android:exported="true" >
+
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity
             android:label="TextView Layout Test"
             android:name=".TextViewInflationActivity"
             android:exported="true" >
diff --git a/startop/apps/test/src/CPUIntensive.java b/startop/apps/test/src/CPUIntensive.java
deleted file mode 100644
index a411e8c..0000000
--- a/startop/apps/test/src/CPUIntensive.java
+++ /dev/null
@@ -1,67 +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.
- */
-
-/**
- *  A threaded CPU intensive class for use in benchmarks.
- */
-
-package com.android.startop.test;
-
-final class CPUIntensive {
-    public static final int THREAD_COUNT = 8;
-    public static final int ARRAY_SIZE = 30000;
-    public static int[][] array = new int[THREAD_COUNT][ARRAY_SIZE];
-
-    static class WorkerThread extends Thread {
-        int mThreadNumber;
-        WorkerThread(int number) {
-            mThreadNumber = number;
-        }
-        public void run() {
-            final int arrayLength = array[mThreadNumber].length;
-            for (int i = 0; i < arrayLength; ++i) {
-                array[mThreadNumber][i] = i * i;
-            }
-            for (int i = 0; i < arrayLength; ++i) {
-                for (int j = 0; j < arrayLength; ++j) {
-                    int swap = array[mThreadNumber][j];
-                    array[mThreadNumber][j] = array[mThreadNumber][(j + i) % arrayLength];
-                    array[mThreadNumber][(j + i) % arrayLength] = swap;
-                }
-            }
-        }
-    };
-
-    public static void doSomeWork(int threadCount) {
-        WorkerThread[] threads = new WorkerThread[threadCount];
-        // Create the threads.
-        for (int i = 0; i < threadCount; ++i) {
-            threads[i] = new WorkerThread(i);
-        }
-        // Start the threads.
-        for (int i = 0; i < threadCount; ++i) {
-            threads[i].start();
-        }
-        // Join the threads.
-        for (int i = 0; i < threadCount; ++i) {
-            try {
-                threads[i].join();
-            } catch (Exception ex) {
-            }
-        }
-    }
-}
-
diff --git a/startop/apps/test/src/CPUIntensiveBenchmarkActivity.java b/startop/apps/test/src/CPUIntensiveBenchmarkActivity.java
new file mode 100644
index 0000000..2ec5308
--- /dev/null
+++ b/startop/apps/test/src/CPUIntensiveBenchmarkActivity.java
@@ -0,0 +1,30 @@
+/*
+ * 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.startop.test;
+
+import android.os.Bundle;
+
+public class CPUIntensiveBenchmarkActivity extends SystemServerBenchmarkActivity {
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.system_server_benchmark_page);
+
+        mBenchmarkList = findViewById(R.id.benchmark_list);
+
+        CPUIntensiveBenchmarks.initializeBenchmarks(this, this);
+    }
+}
diff --git a/startop/apps/test/src/CPUIntensiveBenchmarks.java b/startop/apps/test/src/CPUIntensiveBenchmarks.java
new file mode 100644
index 0000000..19d0b63
--- /dev/null
+++ b/startop/apps/test/src/CPUIntensiveBenchmarks.java
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+/**
+ *  A threaded CPU intensive class for use in benchmarks.
+ */
+
+package com.android.startop.test;
+
+import android.app.Activity;
+
+public class CPUIntensiveBenchmarks {
+    public static final int ARRAY_SIZE = 30000;
+    public static int[][] mArray;
+
+    static class WorkerThread extends Thread {
+        int mThreadNumber;
+        WorkerThread(int number) {
+            mThreadNumber = number;
+        }
+        public void run() {
+            final int arrayLength = mArray[mThreadNumber].length;
+            for (int i = 0; i < arrayLength; ++i) {
+                mArray[mThreadNumber][i] = i * i;
+            }
+            for (int i = 0; i < arrayLength; ++i) {
+                for (int j = 0; j < arrayLength; ++j) {
+                    int swap = mArray[mThreadNumber][j];
+                    mArray[mThreadNumber][j] = mArray[mThreadNumber][(j + i) % arrayLength];
+                    mArray[mThreadNumber][(j + i) % arrayLength] = swap;
+                }
+            }
+        }
+    };
+
+    static void doSomeWork(int threadCount) {
+        mArray = new int[threadCount][ARRAY_SIZE];
+        WorkerThread[] threads = new WorkerThread[threadCount];
+        // Create the threads.
+        for (int i = 0; i < threadCount; ++i) {
+            threads[i] = new WorkerThread(i);
+        }
+        // Start the threads.
+        for (int i = 0; i < threadCount; ++i) {
+            threads[i].start();
+        }
+        // Join the threads.
+        for (int i = 0; i < threadCount; ++i) {
+            try {
+                threads[i].join();
+            } catch (Exception ex) {
+            }
+        }
+    }
+
+    // Time limit to run benchmarks in seconds
+    public static final int TIME_LIMIT = 5;
+
+    static void initializeBenchmarks(Activity parent, BenchmarkRunner benchmarks) {
+        benchmarks.addBenchmark("Use 1 thread", () -> {
+            doSomeWork(1);
+        });
+        benchmarks.addBenchmark("Use 2 threads", () -> {
+            doSomeWork(2);
+        });
+        benchmarks.addBenchmark("Use 4 threads", () -> {
+            doSomeWork(4);
+        });
+        benchmarks.addBenchmark("Use 8 threads", () -> {
+            doSomeWork(8);
+        });
+        benchmarks.addBenchmark("Use 16 threads", () -> {
+            doSomeWork(16);
+        });
+    }
+}
diff --git a/startop/apps/test/src/InitCheckOverheadBenchmarkActivity.java b/startop/apps/test/src/InitCheckOverheadBenchmarkActivity.java
new file mode 100644
index 0000000..3e0e3b1
--- /dev/null
+++ b/startop/apps/test/src/InitCheckOverheadBenchmarkActivity.java
@@ -0,0 +1,30 @@
+/*
+ * 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.startop.test;
+
+import android.os.Bundle;
+
+public class InitCheckOverheadBenchmarkActivity extends SystemServerBenchmarkActivity {
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.system_server_benchmark_page);
+
+        mBenchmarkList = findViewById(R.id.benchmark_list);
+
+        InitCheckOverheadBenchmarks.initializeBenchmarks(this, this);
+    }
+}
diff --git a/startop/apps/test/src/InitCheckOverheadBenchmarks.java b/startop/apps/test/src/InitCheckOverheadBenchmarks.java
new file mode 100644
index 0000000..79adbbc
--- /dev/null
+++ b/startop/apps/test/src/InitCheckOverheadBenchmarks.java
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+/**
+ *  A test of initialization check costs for AOT.
+ */
+
+package com.android.startop.test;
+
+import android.app.Activity;
+
+import java.util.Random;
+
+public class InitCheckOverheadBenchmarks {
+    public static int mSum;
+    public static int mSum2;
+    public static int mStep;
+    public static int mStep2;
+    public static int mStartingValue;
+
+    static {
+        Random random = new Random();
+        mStep = random.nextInt();
+        mStep2 = random.nextInt();
+        mStartingValue = random.nextInt();
+    };
+
+    static class OtherClass {
+        public static int mStep;
+        public static int mStep2;
+        public static int mStartingValue;
+        static {
+            Random random = new Random();
+            mStep = random.nextInt();
+            mStep2 = random.nextInt();
+            mStartingValue = random.nextInt();
+        };
+    };
+
+    public static void localStaticFor(int iterationCount) {
+        for (int i = 0; i < iterationCount; ++i) {
+            mSum += mStep;
+        }
+    }
+
+    public static void nonLocalStaticFor(int iterationCount) {
+        mSum = OtherClass.mStartingValue;
+        for (int i = 0; i < iterationCount; ++i) {
+            mSum += OtherClass.mStep;
+        }
+    }
+
+    public static void localStaticForTwo(int iterationCount) {
+        for (int i = 0; i < iterationCount; ++i) {
+            mSum += mStep;
+            mSum2 += mStep2;
+        }
+    }
+
+    public static void nonLocalStaticForTwo(int iterationCount) {
+        mSum = OtherClass.mStartingValue;
+        for (int i = 0; i < iterationCount; ++i) {
+            mSum += OtherClass.mStep;
+            mSum2 += OtherClass.mStep2;
+        }
+    }
+
+    public static void localStaticDoWhile(int iterationCount) {
+        int i = 0;
+        do {
+            mSum += mStep;
+            ++i;
+        } while (i < iterationCount);
+    }
+
+    public static void nonLocalStaticDoWhile(int iterationCount) {
+        mSum = OtherClass.mStartingValue;
+        int i = 0;
+        do {
+            mSum += OtherClass.mStep;
+            ++i;
+        } while (i < iterationCount);
+    }
+
+    public static void doGC() {
+        Runtime.getRuntime().gc();
+    }
+
+    // Time limit to run benchmarks in seconds
+    public static final int TIME_LIMIT = 5;
+
+    static void initializeBenchmarks(Activity parent, BenchmarkRunner benchmarks) {
+        benchmarks.addBenchmark("GC", () -> {
+            doGC();
+        });
+
+        benchmarks.addBenchmark("InitCheckFor (local)", () -> {
+            localStaticFor(10000000);
+        });
+
+        benchmarks.addBenchmark("InitCheckFor (non-local)", () -> {
+            nonLocalStaticFor(10000000);
+        });
+
+        benchmarks.addBenchmark("InitCheckForTwo (local)", () -> {
+            localStaticForTwo(10000000);
+        });
+
+        benchmarks.addBenchmark("InitCheckForTwo (non-local)", () -> {
+            nonLocalStaticForTwo(10000000);
+        });
+
+        benchmarks.addBenchmark("InitCheckDoWhile (local)", () -> {
+            localStaticDoWhile(10000000);
+        });
+
+        benchmarks.addBenchmark("InitCheckDoWhile (non-local)", () -> {
+            nonLocalStaticDoWhile(10000000);
+        });
+    }
+}
diff --git a/startop/apps/test/src/SystemServerBenchmarkActivity.java b/startop/apps/test/src/SystemServerBenchmarkActivity.java
index 75ea69b..6be8df3 100644
--- a/startop/apps/test/src/SystemServerBenchmarkActivity.java
+++ b/startop/apps/test/src/SystemServerBenchmarkActivity.java
@@ -17,28 +17,20 @@
 package com.android.startop.test;
 
 import android.app.Activity;
-import android.app.ActivityManager;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.AsyncTask;
 import android.os.Bundle;
-import android.view.ViewGroup;
 import android.widget.Button;
 import android.widget.GridLayout;
 import android.widget.TextView;
 
 public class SystemServerBenchmarkActivity extends Activity implements BenchmarkRunner {
-    private GridLayout benchmarkList;
+    protected GridLayout mBenchmarkList;
 
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.system_server_benchmark_page);
 
-        benchmarkList = findViewById(R.id.benchmark_list);
+        mBenchmarkList = findViewById(R.id.benchmark_list);
 
         SystemServerBenchmarks.initializeBenchmarks(this, this);
     }
@@ -49,7 +41,7 @@
      * @param name A short name that shows up in the UI or benchmark results
      */
     public void addBenchmark(CharSequence name, Runnable thunk) {
-        Context context = benchmarkList.getContext();
+        Context context = mBenchmarkList.getContext();
         Button button = new Button(context);
         TextView mean = new TextView(context);
         TextView stdev = new TextView(context);
@@ -68,8 +60,8 @@
             });
         });
 
-        benchmarkList.addView(button);
-        benchmarkList.addView(mean);
-        benchmarkList.addView(stdev);
+        mBenchmarkList.addView(button);
+        mBenchmarkList.addView(mean);
+        mBenchmarkList.addView(stdev);
     }
 }
diff --git a/startop/apps/test/src/SystemServerBenchmarks.java b/startop/apps/test/src/SystemServerBenchmarks.java
index 5918503..25b43f4 100644
--- a/startop/apps/test/src/SystemServerBenchmarks.java
+++ b/startop/apps/test/src/SystemServerBenchmarks.java
@@ -60,22 +60,6 @@
         benchmarks.addBenchmark("Empty", () -> {
         });
 
-        benchmarks.addBenchmark("CPU Intensive (1 thread)", () -> {
-            CPUIntensive.doSomeWork(1);
-        });
-
-        benchmarks.addBenchmark("CPU Intensive (2 thread)", () -> {
-            CPUIntensive.doSomeWork(2);
-        });
-
-        benchmarks.addBenchmark("CPU Intensive (4 thread)", () -> {
-            CPUIntensive.doSomeWork(4);
-        });
-
-        benchmarks.addBenchmark("CPU Intensive (8 thread)", () -> {
-            CPUIntensive.doSomeWork(8);
-        });
-
         PackageManager pm = parent.getPackageManager();
         benchmarks.addBenchmark("getInstalledApplications", () -> {
             pm.getInstalledApplications(PackageManager.MATCH_SYSTEM_ONLY);
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 3f348a4..60290e3 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -2049,6 +2049,10 @@
                 return "DISCONNECTING";
             case STATE_SELECT_PHONE_ACCOUNT:
                 return "SELECT_PHONE_ACCOUNT";
+            case STATE_SIMULATED_RINGING:
+                return "SIMULATED_RINGING";
+            case STATE_AUDIO_PROCESSING:
+                return "AUDIO_PROCESSING";
             default:
                 Log.w(Call.class, "Unknown state %d", state);
                 return "UNKNOWN";
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index fa16b84..20abe77 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -858,7 +858,7 @@
     }
 
     /** @hide */
-    public abstract static class Listener {
+    abstract static class Listener {
         public void onStateChanged(Connection c, int state) {}
         public void onAddressChanged(Connection c, Uri newAddress, int presentation) {}
         public void onCallerDisplayNameChanged(
@@ -2006,7 +2006,7 @@
      *
      * @hide
      */
-    public final Connection addConnectionListener(Listener l) {
+    final Connection addConnectionListener(Listener l) {
         mListeners.add(l);
         return this;
     }
@@ -2019,7 +2019,7 @@
      *
      * @hide
      */
-    public final Connection removeConnectionListener(Listener l) {
+    final Connection removeConnectionListener(Listener l) {
         if (l != null) {
             mListeners.remove(l);
         }
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index bc29b59..dc95f16 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -16,6 +16,7 @@
 
 package android.provider;
 
+import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
@@ -3943,10 +3944,11 @@
     }
 
     /**
-     * Contains received SMS cell broadcast messages. More details are available in 3GPP TS 23.041.
+     * Contains received cell broadcast messages. More details are available in 3GPP TS 23.041.
      * @hide
      */
     @SystemApi
+    @TestApi
     public static final class CellBroadcasts implements BaseColumns {
 
         /**
@@ -3957,11 +3959,44 @@
 
         /**
          * The {@code content://} URI for this table.
+         * Only privileged framework components running on phone or network stack uid can
+         * query or modify this table.
          */
         @NonNull
         public static final Uri CONTENT_URI = Uri.parse("content://cellbroadcasts");
 
         /**
+         * The {@code content://} URI for query cellbroadcast message history.
+         * query results include following entries
+         * <ul>
+         *     <li>{@link #_ID}</li>
+         *     <li>{@link #SLOT_INDEX}</li>
+         *     <li>{@link #GEOGRAPHICAL_SCOPE}</li>
+         *     <li>{@link #PLMN}</li>
+         *     <li>{@link #LAC}</li>
+         *     <li>{@link #CID}</li>
+         *     <li>{@link #SERIAL_NUMBER}</li>
+         *     <li>{@link #SERVICE_CATEGORY}</li>
+         *     <li>{@link #LANGUAGE_CODE}</li>
+         *     <li>{@link #MESSAGE_BODY}</li>
+         *     <li>{@link #DELIVERY_TIME}</li>
+         *     <li>{@link #MESSAGE_READ}</li>
+         *     <li>{@link #MESSAGE_FORMAT}</li>
+         *     <li>{@link #MESSAGE_PRIORITY}</li>
+         *     <li>{@link #ETWS_WARNING_TYPE}</li>
+         *     <li>{@link #CMAS_MESSAGE_CLASS}</li>
+         *     <li>{@link #CMAS_CATEGORY}</li>
+         *     <li>{@link #CMAS_RESPONSE_TYPE}</li>
+         *     <li>{@link #CMAS_SEVERITY}</li>
+         *     <li>{@link #CMAS_URGENCY}</li>
+         *     <li>{@link #CMAS_CERTAINTY}</li>
+         * </ul>
+         */
+        @RequiresPermission(Manifest.permission.READ_CELL_BROADCASTS)
+        @NonNull
+        public static final Uri MESSAGE_HISTORY_URI = Uri.parse("content://cellbroadcasts/history");
+
+        /**
          * The subscription which received this cell broadcast message.
          * @deprecated use {@link #SLOT_INDEX} instead.
          * <P>Type: INTEGER</P>
@@ -3972,7 +4007,6 @@
         /**
          * The slot which received this cell broadcast message.
          * <P>Type: INTEGER</P>
-         * @hide
          */
         public static final String SLOT_INDEX = "slot_index";
 
@@ -4150,14 +4184,12 @@
         /**
          * The timestamp in millisecond of when the device received the message.
          * <P>Type: BIGINT</P>
-         * @hide
          */
         public static final String RECEIVED_TIME = "received_time";
 
         /**
          * Indicates that whether the message has been broadcasted to the application.
          * <P>Type: BOOLEAN</P>
-         * @hide
          */
         public static final String MESSAGE_BROADCASTED = "message_broadcasted";
 
@@ -4193,7 +4225,6 @@
          * "circle|0,0|100;polygon|0,0|0,1.5|1,1|1,0;circle|100.123,100|200.123"
          *
          * <P>Type: TEXT</P>
-         * @hide
          */
         public static final String GEOMETRIES = "geometries";
 
@@ -4205,7 +4236,6 @@
          * for the alert.
          *
          * <P>Type: INTEGER</P>
-         * @hide
          */
         public static final String MAXIMUM_WAIT_TIME = "maximum_wait_time";
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 047b220..dbada25 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -828,13 +828,6 @@
             "disable_severe_when_extreme_disabled_bool";
 
     /**
-     * The message expiration time in milliseconds for duplicate detection purposes.
-     * @hide
-     */
-    public static final String KEY_MESSAGE_EXPIRATION_TIME_LONG =
-            "message_expiration_time_long";
-
-    /**
      * The data call retry configuration for different types of APN.
      * @hide
      */
@@ -1448,6 +1441,15 @@
             "stk_disable_launch_browser_bool";
 
     /**
+      * Boolean indicating if the helper text for STK GET INKEY/INPUT commands with the digit only
+      * mode is displayed on the input screen.
+      * The helper text is dispayed regardless of the input mode, if {@code false}.
+      * @hide
+      */
+    public static final String KEY_HIDE_DIGITS_HELPER_TEXT_ON_STK_INPUT_SCREEN_BOOL =
+            "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
      */
@@ -1829,6 +1831,13 @@
             "support_direct_fdn_dialing_bool";
 
     /**
+     * Int indicating the max number length for FDN
+     * @hide
+     */
+    public static final String KEY_FDN_NUMBER_LENGTH_LIMIT_INT =
+            "fdn_number_length_limit_int";
+
+    /**
      * Report IMEI as device id even if it's a CDMA/LTE phone.
      *
      * @hide
@@ -2872,6 +2881,16 @@
             "always_show_primary_signal_bar_in_opportunistic_network_boolean";
 
     /**
+     * Upon data switching between subscriptions within a carrier group, if switch depends on
+     * validation result, this value defines customized value of how long we wait for validation
+     * success before we fail and revoke the switch.
+     * Time out is in milliseconds.
+     * @hide
+     */
+    public static final String KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG =
+            "data_switch_validation_timeout_long";
+
+    /**
      * GPS configs. See android.hardware.gnss@1.0 IGnssConfiguration.
      * @hide
      */
@@ -3215,6 +3234,14 @@
     public static final String KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY =
             "disconnect_cause_play_busytone_int_array";
 
+    /**
+     * Flag specifying whether to prevent sending CLIR activation("*31#") and deactivation("#31#")
+     * code only without dialing number.
+     * When {@code true}, these are prevented, {@code false} otherwise.
+     */
+    public static final String KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL =
+            "prevent_clir_activation_and_deactivation_code_bool";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -3337,7 +3364,6 @@
         sDefaults.putBoolean(KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL, false);
         sDefaults.putBoolean(KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false);
         sDefaults.putBoolean(KEY_DISABLE_SEVERE_WHEN_EXTREME_DISABLED_BOOL, true);
-        sDefaults.putLong(KEY_MESSAGE_EXPIRATION_TIME_LONG, 86400000L);
         sDefaults.putStringArray(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, new String[]{
                 "default:default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000,"
                         + "320000:5000,640000:5000,1280000:5000,1800000:5000",
@@ -3417,6 +3443,7 @@
         sDefaults.putBoolean(KEY_CDMA_HOME_REGISTERED_PLMN_NAME_OVERRIDE_BOOL, false);
         sDefaults.putString(KEY_CDMA_HOME_REGISTERED_PLMN_NAME_STRING, "");
         sDefaults.putBoolean(KEY_SUPPORT_DIRECT_FDN_DIALING_BOOL, false);
+        sDefaults.putInt(KEY_FDN_NUMBER_LENGTH_LIMIT_INT, 20);
         sDefaults.putBoolean(KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL, false);
         sDefaults.putBoolean(KEY_SKIP_CF_FAIL_TO_DISABLE_DIALOG_BOOL, false);
         sDefaults.putBoolean(KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL, true);
@@ -3525,6 +3552,7 @@
         sDefaults.putBoolean(KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL, false);
         sDefaults.putBoolean(KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL, false);
         sDefaults.putBoolean(KEY_ALLOW_METERED_NETWORK_FOR_CERT_DOWNLOAD_BOOL, false);
+        sDefaults.putBoolean(KEY_HIDE_DIGITS_HELPER_TEXT_ON_STK_INPUT_SCREEN_BOOL, true);
         sDefaults.putStringArray(KEY_CARRIER_WIFI_STRING_ARRAY, null);
         sDefaults.putInt(KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT, -1);
         sDefaults.putInt(KEY_EMERGENCY_NOTIFICATION_DELAY_INT, -1);
@@ -3647,6 +3675,8 @@
         sDefaults.putStringArray(KEY_CARRIER_CERTIFICATE_STRING_ARRAY, null);
         sDefaults.putIntArray(KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY,
                 new int[] {4 /* BUSY */});
+        sDefaults.putBoolean(KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL, false);
+        sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG, 2000);
     }
 
     /**
diff --git a/telephony/java/android/telephony/CellBroadcastService.java b/telephony/java/android/telephony/CellBroadcastService.java
index 46eb9df..09e22aa 100644
--- a/telephony/java/android/telephony/CellBroadcastService.java
+++ b/telephony/java/android/telephony/CellBroadcastService.java
@@ -17,12 +17,19 @@
 package android.telephony;
 
 import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.Service;
 import android.content.Intent;
+import android.os.Bundle;
 import android.os.IBinder;
+import android.os.RemoteCallback;
 import android.telephony.cdma.CdmaSmsCbProgramData;
 
+import java.util.List;
+import java.util.function.Consumer;
+
 /**
  * A service which exposes the cell broadcast handling module to the system.
  * <p>
@@ -46,6 +53,7 @@
  *   </service>
  * </manifest>
  * }</pre>
+ *
  * @hide
  */
 @SystemApi
@@ -62,40 +70,59 @@
 
     /**
      * Handle a GSM cell broadcast SMS message forwarded from the system.
+     *
      * @param slotIndex the index of the slot which received the message
-     * @param message the SMS PDU
+     * @param message   the SMS PDU
      */
-    public abstract void onGsmCellBroadcastSms(int slotIndex, byte[] message);
+    public abstract void onGsmCellBroadcastSms(int slotIndex, @NonNull byte[] message);
 
     /**
      * Handle a CDMA cell broadcast SMS message forwarded from the system.
-     * @param slotIndex the index of the slot which received the message
-     * @param bearerData the CDMA SMS bearer data
+     *
+     * @param slotIndex       the index of the slot which received the message
+     * @param bearerData      the CDMA SMS bearer data
      * @param serviceCategory the CDMA SCPT service category
      */
-    public abstract void onCdmaCellBroadcastSms(int slotIndex, byte[] bearerData,
+    public abstract void onCdmaCellBroadcastSms(int slotIndex, @NonNull byte[] bearerData,
             @CdmaSmsCbProgramData.Category int serviceCategory);
 
     /**
+     * Handle a CDMA cell broadcast SMS message forwarded from the system.
+     *
+     * @param slotIndex          the index of the slot which received the message
+     * @param smsCbProgramData   the SMS CB program data of the message
+     * @param originatingAddress the originating address of the message, as a non-separated dial
+     *                           string
+     * @param callback           a callback to run after each cell broadcast receiver has handled
+     *                           the SCP message. The bundle will contain a non-separated
+     *                           dial string as and an ArrayList of {@link CdmaSmsCbProgramResults}.
+     */
+    public abstract void onCdmaScpMessage(int slotIndex,
+            @NonNull List<CdmaSmsCbProgramData> smsCbProgramData,
+            @NonNull String originatingAddress, @NonNull Consumer<Bundle> callback);
+
+    /**
      * If overriding this method, call through to the super method for any unknown actions.
      * {@inheritDoc}
      */
     @Override
     @CallSuper
-    public IBinder onBind(Intent intent) {
+    public IBinder onBind(@Nullable Intent intent) {
         return mStubWrapper;
     }
 
     /**
      * A wrapper around ICellBroadcastService that forwards calls to implementations of
      * {@link CellBroadcastService}.
+     *
      * @hide
      */
     public class ICellBroadcastServiceWrapper extends ICellBroadcastService.Stub {
         /**
          * Handle a GSM cell broadcast SMS.
+         *
          * @param slotIndex the index of the slot which received the broadcast
-         * @param message the SMS message PDU
+         * @param message   the SMS message PDU
          */
         @Override
         public void handleGsmCellBroadcastSms(int slotIndex, byte[] message) {
@@ -104,8 +131,9 @@
 
         /**
          * Handle a CDMA cell broadcast SMS.
-         * @param slotIndex the index of the slot which received the broadcast
-         * @param bearerData the CDMA SMS bearer data
+         *
+         * @param slotIndex       the index of the slot which received the broadcast
+         * @param bearerData      the CDMA SMS bearer data
          * @param serviceCategory the CDMA SCPT service category
          */
         @Override
@@ -114,5 +142,25 @@
             CellBroadcastService.this.onCdmaCellBroadcastSms(slotIndex, bearerData,
                     serviceCategory);
         }
+
+        /**
+         * Handle a CDMA Service Category Program message.
+         *
+         * @param slotIndex          the index of the slot which received the message
+         * @param smsCbProgramData   the SMS CB program data of the message
+         * @param originatingAddress the originating address of the message
+         * @param callback           a callback to run after each cell broadcast receiver has
+         *                           handled the SCP message
+         */
+        @Override
+        public void handleCdmaScpMessage(int slotIndex,
+                List<CdmaSmsCbProgramData> smsCbProgramData, String originatingAddress,
+                RemoteCallback callback) {
+            Consumer<Bundle> consumer = bundle -> {
+                callback.sendResult(bundle);
+            };
+            CellBroadcastService.this.onCdmaScpMessage(slotIndex, smsCbProgramData,
+                    originatingAddress, consumer);
+        }
     }
 }
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index 1912c60..f9b7f6d 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -194,13 +194,13 @@
     /** @hide */
     @Override
     public void updateLevel(PersistableBundle cc, ServiceState ss) {
-        if (mCsiRsrp == CellInfo.UNAVAILABLE) {
+        if (mSsRsrp == CellInfo.UNAVAILABLE) {
             mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-        } else if (mCsiRsrp >= SIGNAL_GREAT_THRESHOLD) {
+        } else if (mSsRsrp >= SIGNAL_GREAT_THRESHOLD) {
             mLevel = SIGNAL_STRENGTH_GREAT;
-        } else if (mCsiRsrp >= SIGNAL_GOOD_THRESHOLD) {
+        } else if (mSsRsrp >= SIGNAL_GOOD_THRESHOLD) {
             mLevel = SIGNAL_STRENGTH_GOOD;
-        } else if (mCsiRsrp >= SIGNAL_MODERATE_THRESHOLD) {
+        } else if (mSsRsrp >= SIGNAL_MODERATE_THRESHOLD) {
             mLevel = SIGNAL_STRENGTH_MODERATE;
         } else {
             mLevel = SIGNAL_STRENGTH_POOR;
@@ -212,7 +212,7 @@
      *
      * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
      *
-     * @return RSCP in ASU 0..97, 255, or UNAVAILABLE
+     * @return RSRP in ASU 0..97, 255, or UNAVAILABLE
      */
     @Override
     public int getAsuLevel() {
@@ -231,11 +231,11 @@
     }
 
     /**
-     * Get the CSI-RSRP as dBm value -140..-44dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
+     * Get the SS-RSRP as dBm value -140..-44dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
      */
     @Override
     public int getDbm() {
-        return mCsiRsrp;
+        return mSsRsrp;
     }
 
     /** @hide */
diff --git a/telephony/java/android/telephony/ICellBroadcastService.aidl b/telephony/java/android/telephony/ICellBroadcastService.aidl
index bcd6cc5..11263d9 100644
--- a/telephony/java/android/telephony/ICellBroadcastService.aidl
+++ b/telephony/java/android/telephony/ICellBroadcastService.aidl
@@ -16,6 +16,9 @@
 
 package android.telephony;
 
+import android.os.RemoteCallback;
+import android.telephony.cdma.CdmaSmsCbProgramData;
+
 /**
  * Service bound to by the system to allow custom handling of cell broadcast messages.
  * <p>
@@ -29,4 +32,8 @@
 
     /** @see android.telephony.CellBroadcastService#onCdmaCellBroadcastSms */
     oneway void handleCdmaCellBroadcastSms(int slotId, in byte[] bearerData, int serviceCategory);
+
+    /** @see android.telephony.CellBroadcastService#onCdmaScpMessage */
+    oneway void handleCdmaScpMessage(int slotId, in List<CdmaSmsCbProgramData> programData,
+            String originatingAddress, in RemoteCallback callback);
 }
diff --git a/telephony/java/android/telephony/ImsiEncryptionInfo.java b/telephony/java/android/telephony/ImsiEncryptionInfo.java
index ef2f121..75a79d6 100644
--- a/telephony/java/android/telephony/ImsiEncryptionInfo.java
+++ b/telephony/java/android/telephony/ImsiEncryptionInfo.java
@@ -15,9 +15,11 @@
  */
 package android.telephony;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
-import java.util.Date;
 import android.util.Log;
 
 import java.security.KeyFactory;
@@ -25,18 +27,18 @@
 import java.security.PublicKey;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.X509EncodedKeySpec;
+import java.util.Date;
 
 /**
  * Class to represent information sent by the carrier, which will be used to encrypt
  * the IMSI + IMPI. The ecryption is being done by WLAN, and the modem.
- *
  * @hide
  */
+@SystemApi
 public final class ImsiEncryptionInfo implements Parcelable {
 
     private static final String LOG_TAG = "ImsiEncryptionInfo";
 
-
     private final String mcc;
     private final String mnc;
     private final PublicKey publicKey;
@@ -45,11 +47,13 @@
     //Date-Time in UTC when the key will expire.
     private final Date expirationTime;
 
+    /** @hide */
     public ImsiEncryptionInfo(String mcc, String mnc, int keyType, String keyIdentifier,
                               byte[] key, Date expirationTime) {
         this(mcc, mnc, keyType, keyIdentifier, makeKeyObject(key), expirationTime);
     }
 
+    /** @hide */
     public ImsiEncryptionInfo(String mcc, String mnc, int keyType, String keyIdentifier,
                               PublicKey publicKey, Date expirationTime) {
         // todo need to validate that ImsiEncryptionInfo is being created with the correct params.
@@ -63,6 +67,7 @@
         this.expirationTime = expirationTime;
     }
 
+    /** @hide */
     public ImsiEncryptionInfo(Parcel in) {
         int length = in.readInt();
         byte b[] = new byte[length];
@@ -75,26 +80,40 @@
         expirationTime = new Date(in.readLong());
     }
 
+    /** @hide */
     public String getMnc() {
         return this.mnc;
     }
 
+    /** @hide */
     public String getMcc() {
         return this.mcc;
     }
 
+    /**
+     * Returns key identifier, a string that helps the authentication server to locate the
+     * private key to decrypt the permanent identity, or {@code null} when uavailable.
+     */
+    @Nullable
     public String getKeyIdentifier() {
         return this.keyIdentifier;
     }
 
+    /** @hide */
     public int getKeyType() {
         return this.keyType;
     }
 
+    /**
+     * Returns the carrier public key that is used for the IMSI encryption,
+     * or {@code null} when uavailable.
+     */
+    @Nullable
     public PublicKey getPublicKey() {
         return this.publicKey;
     }
 
+    /** @hide */
     public Date getExpirationTime() {
         return this.expirationTime;
     }
@@ -115,7 +134,7 @@
         return 0;
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<ImsiEncryptionInfo> CREATOR =
+    public static final @NonNull Parcelable.Creator<ImsiEncryptionInfo> CREATOR =
             new Parcelable.Creator<ImsiEncryptionInfo>() {
                 @Override
                 public ImsiEncryptionInfo createFromParcel(Parcel in) {
@@ -129,7 +148,7 @@
             };
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         byte[] b = publicKey.getEncoded();
         dest.writeInt(b.length);
         dest.writeByteArray(b);
diff --git a/telephony/java/android/telephony/LocationAccessPolicy.java b/telephony/java/android/telephony/LocationAccessPolicy.java
index eb744f6..79b3756 100644
--- a/telephony/java/android/telephony/LocationAccessPolicy.java
+++ b/telephony/java/android/telephony/LocationAccessPolicy.java
@@ -18,6 +18,7 @@
 
 import android.Manifest;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
@@ -59,6 +60,7 @@
 
     public static class LocationPermissionQuery {
         public final String callingPackage;
+        public final String callingFeatureId;
         public final int callingUid;
         public final int callingPid;
         public final int minSdkVersionForCoarse;
@@ -66,10 +68,11 @@
         public final boolean logAsInfo;
         public final String method;
 
-        private LocationPermissionQuery(String callingPackage, int callingUid, int callingPid,
-                int minSdkVersionForCoarse, int minSdkVersionForFine, boolean logAsInfo,
-                String method) {
+        private LocationPermissionQuery(String callingPackage, @Nullable String callingFeatureId,
+                int callingUid, int callingPid, int minSdkVersionForCoarse,
+                int minSdkVersionForFine, boolean logAsInfo, String method) {
             this.callingPackage = callingPackage;
+            this.callingFeatureId = callingFeatureId;
             this.callingUid = callingUid;
             this.callingPid = callingPid;
             this.minSdkVersionForCoarse = minSdkVersionForCoarse;
@@ -80,6 +83,7 @@
 
         public static class Builder {
             private String mCallingPackage;
+            private String mCallingFeatureId;
             private int mCallingUid;
             private int mCallingPid;
             private int mMinSdkVersionForCoarse = Integer.MAX_VALUE;
@@ -98,6 +102,14 @@
             /**
              * Mandatory parameter, used for performing permission checks.
              */
+            public Builder setCallingFeatureId(@Nullable String callingFeatureId) {
+                mCallingFeatureId = callingFeatureId;
+                return this;
+            }
+
+            /**
+             * Mandatory parameter, used for performing permission checks.
+             */
             public Builder setCallingUid(int callingUid) {
                 mCallingUid = callingUid;
                 return this;
@@ -148,8 +160,8 @@
             }
 
             public LocationPermissionQuery build() {
-                return new LocationPermissionQuery(mCallingPackage, mCallingUid,
-                        mCallingPid, mMinSdkVersionForCoarse, mMinSdkVersionForFine,
+                return new LocationPermissionQuery(mCallingPackage, mCallingFeatureId,
+                        mCallingUid, mCallingPid, mMinSdkVersionForCoarse, mMinSdkVersionForFine,
                         mLogAsInfo, mMethod);
             }
         }
@@ -195,7 +207,7 @@
             // Only check the app op if the app has the permission.
             int appOpMode = context.getSystemService(AppOpsManager.class)
                     .noteOpNoThrow(AppOpsManager.permissionToOpCode(permissionToCheck),
-                            query.callingUid, query.callingPackage);
+                            query.callingUid, query.callingPackage, query.callingFeatureId, null);
             if (appOpMode == AppOpsManager.MODE_ALLOWED) {
                 // If the app did everything right, return without logging.
                 return LocationPermissionResult.ALLOWED;
@@ -339,4 +351,4 @@
         }
         return false;
     }
-}
\ No newline at end of file
+}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 2d35f8e..2c16110 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -28,17 +28,13 @@
 import android.app.ActivityThread;
 import android.app.PendingIntent;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.database.CursorWindow;
 import android.net.Uri;
-import android.os.Binder;
-import android.os.BaseBundle;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.provider.Telephony;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -290,12 +286,6 @@
      */
     public static final int SMS_MESSAGE_PERIOD_NOT_SPECIFIED = -1;
 
-    /**
-     * Extra key passed into a PendingIntent when the SMS operation failed due to there being no
-     * default set.
-     */
-    private static final String NO_DEFAULT_EXTRA = "noDefault";
-
     // result of asking the user for a subscription to perform an operation.
     private interface SubscriptionResolverResult {
         void onSuccess(int subId);
@@ -336,9 +326,59 @@
      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
      *  <code>RESULT_ERROR_NULL_PDU</code><br>
      *  <code>RESULT_ERROR_NO_SERVICE</code><br>
-     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
-     *  the extra "errorCode" containing a radio technology specific value,
-     *  generally only useful for troubleshooting.<br>
+     *  <code>RESULT_ERROR_NO_SERVICE</code><br>
+     *  <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br>
+     *  <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
+     *  <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
+     *  <code>RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br>
+     *  <code>RESULT_RADIO_NOT_AVAILABLE</code><br>
+     *  <code>RESULT_NETWORK_REJECT</code><br>
+     *  <code>RESULT_INVALID_ARGUMENTS</code><br>
+     *  <code>RESULT_INVALID_STATE</code><br>
+     *  <code>RESULT_NO_MEMORY</code><br>
+     *  <code>RESULT_INVALID_SMS_FORMAT</code><br>
+     *  <code>RESULT_SYSTEM_ERROR</code><br>
+     *  <code>RESULT_MODEM_ERROR</code><br>
+     *  <code>RESULT_NETWORK_ERROR</code><br>
+     *  <code>RESULT_ENCODING_ERROR</code><br>
+     *  <code>RESULT_INVALID_SMSC_ADDRESS</code><br>
+     *  <code>RESULT_OPERATION_NOT_ALLOWED</code><br>
+     *  <code>RESULT_INTERNAL_ERROR</code><br>
+     *  <code>RESULT_NO_RESOURCES</code><br>
+     *  <code>RESULT_CANCELLED</code><br>
+     *  <code>RESULT_REQUEST_NOT_SUPPORTED</code><br>
+     *  <code>RESULT_NO_BLUETOOTH_SERVICE</code><br>
+     *  <code>RESULT_INVALID_BLUETOOTH_ADDRESS</code><br>
+     *  <code>RESULT_BLUETOOTH_DISCONNECTED</code><br>
+     *  <code>RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br>
+     *  <code>RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br>
+     *  <code>RESULT_SMS_SEND_RETRY_FAILED</code><br>
+     *  <code>RESULT_REMOTE_EXCEPTION</code><br>
+     *  <code>RESULT_NO_DEFAULT_SMS_APP</code><br>
+     *  <code>RESULT_RIL_RADIO_NOT_AVAILABLE</code><br>
+     *  <code>RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br>
+     *  <code>RESULT_RIL_NETWORK_REJECT</code><br>
+     *  <code>RESULT_RIL_INVALID_STATE</code><br>
+     *  <code>RESULT_RIL_INVALID_ARGUMENTS</code><br>
+     *  <code>RESULT_RIL_NO_MEMORY</code><br>
+     *  <code>RESULT_RIL_REQUEST_RATE_LIMITED</code><br>
+     *  <code>RESULT_RIL_INVALID_SMS_FORMAT</code><br>
+     *  <code>RESULT_RIL_SYSTEM_ERR</code><br>
+     *  <code>RESULT_RIL_ENCODING_ERR</code><br>
+     *  <code>RESULT_RIL_INVALID_SMSC_ADDRESS</code><br>
+     *  <code>RESULT_RIL_MODEM_ERR</code><br>
+     *  <code>RESULT_RIL_NETWORK_ERR</code><br>
+     *  <code>RESULT_RIL_INTERNAL_ERR</code><br>
+     *  <code>RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br>
+     *  <code>RESULT_RIL_INVALID_MODEM_STATE</code><br>
+     *  <code>RESULT_RIL_NETWORK_NOT_READY</code><br>
+     *  <code>RESULT_RIL_OPERATION_NOT_ALLOWED</code><br>
+     *  <code>RESULT_RIL_NO_RESOURCES</code><br>
+     *  <code>RESULT_RIL_CANCELLED</code><br>
+     *  <code>RESULT_RIL_SIM_ABSENT</code><br>
+     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors,
+     *  the sentIntent may include the extra "errorCode" containing a radio technology specific
+     *  value, generally only useful for troubleshooting.<br>
      *  The per-application based SMS control checks sentIntent. If sentIntent
      *  is NULL the caller will be checked against all unknown applications,
      *  which cause smaller number of SMS to be sent in checking period.
@@ -378,9 +418,60 @@
      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
      *  <code>RESULT_ERROR_NULL_PDU</code><br>
-     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
-     *  the extra "errorCode" containing a radio technology specific value,
-     *  generally only useful for troubleshooting.<br>
+     *  <code>RESULT_ERROR_NO_SERVICE</code><br>
+     *  <code>RESULT_ERROR_NO_SERVICE</code><br>
+     *  <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br>
+     *  <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
+     *  <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
+     *  <code>RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br>
+     *  <code>RESULT_RADIO_NOT_AVAILABLE</code><br>
+     *  <code>RESULT_NETWORK_REJECT</code><br>
+     *  <code>RESULT_INVALID_ARGUMENTS</code><br>
+     *  <code>RESULT_INVALID_STATE</code><br>
+     *  <code>RESULT_NO_MEMORY</code><br>
+     *  <code>RESULT_INVALID_SMS_FORMAT</code><br>
+     *  <code>RESULT_SYSTEM_ERROR</code><br>
+     *  <code>RESULT_MODEM_ERROR</code><br>
+     *  <code>RESULT_NETWORK_ERROR</code><br>
+     *  <code>RESULT_ENCODING_ERROR</code><br>
+     *  <code>RESULT_INVALID_SMSC_ADDRESS</code><br>
+     *  <code>RESULT_OPERATION_NOT_ALLOWED</code><br>
+     *  <code>RESULT_INTERNAL_ERROR</code><br>
+     *  <code>RESULT_NO_RESOURCES</code><br>
+     *  <code>RESULT_CANCELLED</code><br>
+     *  <code>RESULT_REQUEST_NOT_SUPPORTED</code><br>
+     *  <code>RESULT_NO_BLUETOOTH_SERVICE</code><br>
+     *  <code>RESULT_INVALID_BLUETOOTH_ADDRESS</code><br>
+     *  <code>RESULT_BLUETOOTH_DISCONNECTED</code><br>
+     *  <code>RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br>
+     *  <code>RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br>
+     *  <code>RESULT_SMS_SEND_RETRY_FAILED</code><br>
+     *  <code>RESULT_REMOTE_EXCEPTION</code><br>
+     *  <code>RESULT_NO_DEFAULT_SMS_APP</code><br>
+     *  <code>RESULT_RIL_RADIO_NOT_AVAILABLE</code><br>
+     *  <code>RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br>
+     *  <code>RESULT_RIL_NETWORK_REJECT</code><br>
+     *  <code>RESULT_RIL_INVALID_STATE</code><br>
+     *  <code>RESULT_RIL_INVALID_ARGUMENTS</code><br>
+     *  <code>RESULT_RIL_NO_MEMORY</code><br>
+     *  <code>RESULT_RIL_REQUEST_RATE_LIMITED</code><br>
+     *  <code>RESULT_RIL_INVALID_SMS_FORMAT</code><br>
+     *  <code>RESULT_RIL_SYSTEM_ERR</code><br>
+     *  <code>RESULT_RIL_ENCODING_ERR</code><br>
+     *  <code>RESULT_RIL_INVALID_SMSC_ADDRESS</code><br>
+     *  <code>RESULT_RIL_MODEM_ERR</code><br>
+     *  <code>RESULT_RIL_NETWORK_ERR</code><br>
+     *  <code>RESULT_RIL_INTERNAL_ERR</code><br>
+     *  <code>RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br>
+     *  <code>RESULT_RIL_INVALID_MODEM_STATE</code><br>
+     *  <code>RESULT_RIL_NETWORK_NOT_READY</code><br>
+     *  <code>RESULT_RIL_OPERATION_NOT_ALLOWED</code><br>
+     *  <code>RESULT_RIL_NO_RESOURCES</code><br>
+     *  <code>RESULT_RIL_CANCELLED</code><br>
+     *  <code>RESULT_RIL_SIM_ABSENT</code><br>
+     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors,
+     *  the sentIntent may include the extra "errorCode" containing a radio technology specific
+     *  value, generally only useful for troubleshooting.<br>
      *  The per-application based SMS control checks sentIntent. If sentIntent
      *  is NULL the caller will be checked against all unknown applications,
      *  which cause smaller number of SMS to be sent in checking period.
@@ -451,13 +542,13 @@
                     } catch (RemoteException e) {
                         Log.e(TAG, "sendTextMessageInternal: Couldn't send SMS, exception - "
                                 + e.getMessage());
-                        notifySmsGenericError(sentIntent);
+                        notifySmsError(sentIntent, RESULT_REMOTE_EXCEPTION);
                     }
                 }
 
                 @Override
                 public void onFailure() {
-                    notifySmsErrorNoDefaultSet(context, sentIntent);
+                    notifySmsError(sentIntent, RESULT_NO_DEFAULT_SMS_APP);
                 }
             });
         } else {
@@ -471,7 +562,7 @@
             } catch (RemoteException e) {
                 Log.e(TAG, "sendTextMessageInternal (no persist): Couldn't send SMS, exception - "
                         + e.getMessage());
-                notifySmsGenericError(sentIntent);
+                notifySmsError(sentIntent, RESULT_REMOTE_EXCEPTION);
             }
         }
     }
@@ -564,13 +655,13 @@
                     } catch (RemoteException e) {
                         Log.e(TAG, "sendTextMessageInternal: Couldn't send SMS, exception - "
                                 + e.getMessage());
-                        notifySmsGenericError(sentIntent);
+                        notifySmsError(sentIntent, RESULT_REMOTE_EXCEPTION);
                     }
                 }
 
                 @Override
                 public void onFailure() {
-                    notifySmsErrorNoDefaultSet(context, sentIntent);
+                    notifySmsError(sentIntent, RESULT_NO_DEFAULT_SMS_APP);
                 }
             });
         } else {
@@ -586,7 +677,7 @@
             } catch (RemoteException e) {
                 Log.e(TAG, "sendTextMessageInternal(no persist): Couldn't send SMS, exception - "
                         + e.getMessage());
-                notifySmsGenericError(sentIntent);
+                notifySmsError(sentIntent, RESULT_REMOTE_EXCEPTION);
             }
         }
     }
@@ -668,7 +759,7 @@
         } catch (RemoteException ex) {
             try {
                 if (receivedIntent != null) {
-                    receivedIntent.send(Telephony.Sms.Intents.RESULT_SMS_GENERIC_ERROR);
+                    receivedIntent.send(RESULT_REMOTE_EXCEPTION);
                 }
             } catch (PendingIntent.CanceledException cx) {
                 // Don't worry about it, we do not need to notify the caller if this is the case.
@@ -724,12 +815,63 @@
      *   broadcast when the corresponding message part has been sent.
      *   The result code will be <code>Activity.RESULT_OK</code> for success,
      *   or one of these errors:<br>
-     *   <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
-     *   <code>RESULT_ERROR_RADIO_OFF</code><br>
-     *   <code>RESULT_ERROR_NULL_PDU</code><br>
-     *   For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
-     *   the extra "errorCode" containing a radio technology specific value,
-     *   generally only useful for troubleshooting.<br>
+     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
+     *  <code>RESULT_ERROR_NULL_PDU</code><br>
+     *  <code>RESULT_ERROR_NO_SERVICE</code><br>
+     *  <code>RESULT_ERROR_NO_SERVICE</code><br>
+     *  <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br>
+     *  <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
+     *  <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
+     *  <code>RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br>
+     *  <code>RESULT_RADIO_NOT_AVAILABLE</code><br>
+     *  <code>RESULT_NETWORK_REJECT</code><br>
+     *  <code>RESULT_INVALID_ARGUMENTS</code><br>
+     *  <code>RESULT_INVALID_STATE</code><br>
+     *  <code>RESULT_NO_MEMORY</code><br>
+     *  <code>RESULT_INVALID_SMS_FORMAT</code><br>
+     *  <code>RESULT_SYSTEM_ERROR</code><br>
+     *  <code>RESULT_MODEM_ERROR</code><br>
+     *  <code>RESULT_NETWORK_ERROR</code><br>
+     *  <code>RESULT_ENCODING_ERROR</code><br>
+     *  <code>RESULT_INVALID_SMSC_ADDRESS</code><br>
+     *  <code>RESULT_OPERATION_NOT_ALLOWED</code><br>
+     *  <code>RESULT_INTERNAL_ERROR</code><br>
+     *  <code>RESULT_NO_RESOURCES</code><br>
+     *  <code>RESULT_CANCELLED</code><br>
+     *  <code>RESULT_REQUEST_NOT_SUPPORTED</code><br>
+     *  <code>RESULT_NO_BLUETOOTH_SERVICE</code><br>
+     *  <code>RESULT_INVALID_BLUETOOTH_ADDRESS</code><br>
+     *  <code>RESULT_BLUETOOTH_DISCONNECTED</code><br>
+     *  <code>RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br>
+     *  <code>RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br>
+     *  <code>RESULT_SMS_SEND_RETRY_FAILED</code><br>
+     *  <code>RESULT_REMOTE_EXCEPTION</code><br>
+     *  <code>RESULT_NO_DEFAULT_SMS_APP</code><br>
+     *  <code>RESULT_RIL_RADIO_NOT_AVAILABLE</code><br>
+     *  <code>RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br>
+     *  <code>RESULT_RIL_NETWORK_REJECT</code><br>
+     *  <code>RESULT_RIL_INVALID_STATE</code><br>
+     *  <code>RESULT_RIL_INVALID_ARGUMENTS</code><br>
+     *  <code>RESULT_RIL_NO_MEMORY</code><br>
+     *  <code>RESULT_RIL_REQUEST_RATE_LIMITED</code><br>
+     *  <code>RESULT_RIL_INVALID_SMS_FORMAT</code><br>
+     *  <code>RESULT_RIL_SYSTEM_ERR</code><br>
+     *  <code>RESULT_RIL_ENCODING_ERR</code><br>
+     *  <code>RESULT_RIL_INVALID_SMSC_ADDRESS</code><br>
+     *  <code>RESULT_RIL_MODEM_ERR</code><br>
+     *  <code>RESULT_RIL_NETWORK_ERR</code><br>
+     *  <code>RESULT_RIL_INTERNAL_ERR</code><br>
+     *  <code>RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br>
+     *  <code>RESULT_RIL_INVALID_MODEM_STATE</code><br>
+     *  <code>RESULT_RIL_NETWORK_NOT_READY</code><br>
+     *  <code>RESULT_RIL_OPERATION_NOT_ALLOWED</code><br>
+     *  <code>RESULT_RIL_NO_RESOURCES</code><br>
+     *  <code>RESULT_RIL_CANCELLED</code><br>
+     *  <code>RESULT_RIL_SIM_ABSENT</code><br>
+     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors,
+     *  the sentIntent may include the extra "errorCode" containing a radio technology specific
+     *  value, generally only useful for troubleshooting.<br>
      *   The per-application based SMS control checks sentIntent. If sentIntent
      *   is NULL the caller will be checked against all unknown applications,
      *   which cause smaller number of SMS to be sent in checking period.
@@ -811,13 +953,13 @@
                         } catch (RemoteException e) {
                             Log.e(TAG, "sendMultipartTextMessageInternal: Couldn't send SMS - "
                                     + e.getMessage());
-                            notifySmsGenericError(sentIntents);
+                            notifySmsError(sentIntents, RESULT_REMOTE_EXCEPTION);
                         }
                     }
 
                     @Override
                     public void onFailure() {
-                        notifySmsErrorNoDefaultSet(context, sentIntents);
+                        notifySmsError(sentIntents, RESULT_NO_DEFAULT_SMS_APP);
                     }
                 });
             } else {
@@ -832,7 +974,7 @@
                 } catch (RemoteException e) {
                     Log.e(TAG, "sendMultipartTextMessageInternal: Couldn't send SMS - "
                             + e.getMessage());
-                    notifySmsGenericError(sentIntents);
+                    notifySmsError(sentIntents, RESULT_REMOTE_EXCEPTION);
                 }
             }
         } else {
@@ -911,12 +1053,63 @@
      *   broadcast when the corresponding message part has been sent.
      *   The result code will be <code>Activity.RESULT_OK</code> for success,
      *   or one of these errors:<br>
-     *   <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
-     *   <code>RESULT_ERROR_RADIO_OFF</code><br>
-     *   <code>RESULT_ERROR_NULL_PDU</code><br>
-     *   For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
-     *   the extra "errorCode" containing a radio technology specific value,
-     *   generally only useful for troubleshooting.<br>
+     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
+     *  <code>RESULT_ERROR_NULL_PDU</code><br>
+     *  <code>RESULT_ERROR_NO_SERVICE</code><br>
+     *  <code>RESULT_ERROR_NO_SERVICE</code><br>
+     *  <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br>
+     *  <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
+     *  <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
+     *  <code>RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br>
+     *  <code>RESULT_RADIO_NOT_AVAILABLE</code><br>
+     *  <code>RESULT_NETWORK_REJECT</code><br>
+     *  <code>RESULT_INVALID_ARGUMENTS</code><br>
+     *  <code>RESULT_INVALID_STATE</code><br>
+     *  <code>RESULT_NO_MEMORY</code><br>
+     *  <code>RESULT_INVALID_SMS_FORMAT</code><br>
+     *  <code>RESULT_SYSTEM_ERROR</code><br>
+     *  <code>RESULT_MODEM_ERROR</code><br>
+     *  <code>RESULT_NETWORK_ERROR</code><br>
+     *  <code>RESULT_ENCODING_ERROR</code><br>
+     *  <code>RESULT_INVALID_SMSC_ADDRESS</code><br>
+     *  <code>RESULT_OPERATION_NOT_ALLOWED</code><br>
+     *  <code>RESULT_INTERNAL_ERROR</code><br>
+     *  <code>RESULT_NO_RESOURCES</code><br>
+     *  <code>RESULT_CANCELLED</code><br>
+     *  <code>RESULT_REQUEST_NOT_SUPPORTED</code><br>
+     *  <code>RESULT_NO_BLUETOOTH_SERVICE</code><br>
+     *  <code>RESULT_INVALID_BLUETOOTH_ADDRESS</code><br>
+     *  <code>RESULT_BLUETOOTH_DISCONNECTED</code><br>
+     *  <code>RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br>
+     *  <code>RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br>
+     *  <code>RESULT_SMS_SEND_RETRY_FAILED</code><br>
+     *  <code>RESULT_REMOTE_EXCEPTION</code><br>
+     *  <code>RESULT_NO_DEFAULT_SMS_APP</code><br>
+     *  <code>RESULT_RIL_RADIO_NOT_AVAILABLE</code><br>
+     *  <code>RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br>
+     *  <code>RESULT_RIL_NETWORK_REJECT</code><br>
+     *  <code>RESULT_RIL_INVALID_STATE</code><br>
+     *  <code>RESULT_RIL_INVALID_ARGUMENTS</code><br>
+     *  <code>RESULT_RIL_NO_MEMORY</code><br>
+     *  <code>RESULT_RIL_REQUEST_RATE_LIMITED</code><br>
+     *  <code>RESULT_RIL_INVALID_SMS_FORMAT</code><br>
+     *  <code>RESULT_RIL_SYSTEM_ERR</code><br>
+     *  <code>RESULT_RIL_ENCODING_ERR</code><br>
+     *  <code>RESULT_RIL_INVALID_SMSC_ADDRESS</code><br>
+     *  <code>RESULT_RIL_MODEM_ERR</code><br>
+     *  <code>RESULT_RIL_NETWORK_ERR</code><br>
+     *  <code>RESULT_RIL_INTERNAL_ERR</code><br>
+     *  <code>RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br>
+     *  <code>RESULT_RIL_INVALID_MODEM_STATE</code><br>
+     *  <code>RESULT_RIL_NETWORK_NOT_READY</code><br>
+     *  <code>RESULT_RIL_OPERATION_NOT_ALLOWED</code><br>
+     *  <code>RESULT_RIL_NO_RESOURCES</code><br>
+     *  <code>RESULT_RIL_CANCELLED</code><br>
+     *  <code>RESULT_RIL_SIM_ABSENT</code><br>
+     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors,
+     *  the sentIntent may include the extra "errorCode" containing a radio technology specific
+     *  value, generally only useful for troubleshooting.<br>
      *   The per-application based SMS control checks sentIntent. If sentIntent
      *   is NULL the caller will be checked against all unknown applications,
      *   which cause smaller number of SMS to be sent in checking period.
@@ -994,13 +1187,13 @@
                         } catch (RemoteException e) {
                             Log.e(TAG, "sendMultipartTextMessageInternal: Couldn't send SMS - "
                                     + e.getMessage());
-                            notifySmsGenericError(sentIntents);
+                            notifySmsError(sentIntents, RESULT_REMOTE_EXCEPTION);
                         }
                     }
 
                     @Override
                     public void onFailure() {
-                        notifySmsErrorNoDefaultSet(context, sentIntents);
+                        notifySmsError(sentIntents, RESULT_NO_DEFAULT_SMS_APP);
                     }
                 });
             } else {
@@ -1016,7 +1209,7 @@
                 } catch (RemoteException e) {
                     Log.e(TAG, "sendMultipartTextMessageInternal (no persist): Couldn't send SMS - "
                             + e.getMessage());
-                    notifySmsGenericError(sentIntents);
+                    notifySmsError(sentIntents, RESULT_REMOTE_EXCEPTION);
                 }
             }
         } else {
@@ -1061,9 +1254,60 @@
      *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
      *  <code>RESULT_ERROR_RADIO_OFF</code><br>
      *  <code>RESULT_ERROR_NULL_PDU</code><br>
-     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
-     *  the extra "errorCode" containing a radio technology specific value,
-     *  generally only useful for troubleshooting.<br>
+     *  <code>RESULT_ERROR_NO_SERVICE</code><br>
+     *  <code>RESULT_ERROR_NO_SERVICE</code><br>
+     *  <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br>
+     *  <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br>
+     *  <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br>
+     *  <code>RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br>
+     *  <code>RESULT_RADIO_NOT_AVAILABLE</code><br>
+     *  <code>RESULT_NETWORK_REJECT</code><br>
+     *  <code>RESULT_INVALID_ARGUMENTS</code><br>
+     *  <code>RESULT_INVALID_STATE</code><br>
+     *  <code>RESULT_NO_MEMORY</code><br>
+     *  <code>RESULT_INVALID_SMS_FORMAT</code><br>
+     *  <code>RESULT_SYSTEM_ERROR</code><br>
+     *  <code>RESULT_MODEM_ERROR</code><br>
+     *  <code>RESULT_NETWORK_ERROR</code><br>
+     *  <code>RESULT_ENCODING_ERROR</code><br>
+     *  <code>RESULT_INVALID_SMSC_ADDRESS</code><br>
+     *  <code>RESULT_OPERATION_NOT_ALLOWED</code><br>
+     *  <code>RESULT_INTERNAL_ERROR</code><br>
+     *  <code>RESULT_NO_RESOURCES</code><br>
+     *  <code>RESULT_CANCELLED</code><br>
+     *  <code>RESULT_REQUEST_NOT_SUPPORTED</code><br>
+     *  <code>RESULT_NO_BLUETOOTH_SERVICE</code><br>
+     *  <code>RESULT_INVALID_BLUETOOTH_ADDRESS</code><br>
+     *  <code>RESULT_BLUETOOTH_DISCONNECTED</code><br>
+     *  <code>RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br>
+     *  <code>RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br>
+     *  <code>RESULT_SMS_SEND_RETRY_FAILED</code><br>
+     *  <code>RESULT_REMOTE_EXCEPTION</code><br>
+     *  <code>RESULT_NO_DEFAULT_SMS_APP</code><br>
+     *  <code>RESULT_RIL_RADIO_NOT_AVAILABLE</code><br>
+     *  <code>RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br>
+     *  <code>RESULT_RIL_NETWORK_REJECT</code><br>
+     *  <code>RESULT_RIL_INVALID_STATE</code><br>
+     *  <code>RESULT_RIL_INVALID_ARGUMENTS</code><br>
+     *  <code>RESULT_RIL_NO_MEMORY</code><br>
+     *  <code>RESULT_RIL_REQUEST_RATE_LIMITED</code><br>
+     *  <code>RESULT_RIL_INVALID_SMS_FORMAT</code><br>
+     *  <code>RESULT_RIL_SYSTEM_ERR</code><br>
+     *  <code>RESULT_RIL_ENCODING_ERR</code><br>
+     *  <code>RESULT_RIL_INVALID_SMSC_ADDRESS</code><br>
+     *  <code>RESULT_RIL_MODEM_ERR</code><br>
+     *  <code>RESULT_RIL_NETWORK_ERR</code><br>
+     *  <code>RESULT_RIL_INTERNAL_ERR</code><br>
+     *  <code>RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br>
+     *  <code>RESULT_RIL_INVALID_MODEM_STATE</code><br>
+     *  <code>RESULT_RIL_NETWORK_NOT_READY</code><br>
+     *  <code>RESULT_RIL_OPERATION_NOT_ALLOWED</code><br>
+     *  <code>RESULT_RIL_NO_RESOURCES</code><br>
+     *  <code>RESULT_RIL_CANCELLED</code><br>
+     *  <code>RESULT_RIL_SIM_ABSENT</code><br>
+     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors,
+     *  the sentIntent may include the extra "errorCode" containing a radio technology specific
+     *  value, generally only useful for troubleshooting.<br>
      *  The per-application based SMS control checks sentIntent. If sentIntent
      *  is NULL the caller will be checked against all unknown applications,
      *  which cause smaller number of SMS to be sent in checking period.
@@ -1095,12 +1339,12 @@
                             sentIntent, deliveryIntent);
                 } catch (RemoteException e) {
                     Log.e(TAG, "sendDataMessage: Couldn't send SMS - Exception: " + e.getMessage());
-                    notifySmsGenericError(sentIntent);
+                    notifySmsError(sentIntent, RESULT_REMOTE_EXCEPTION);
                 }
             }
             @Override
             public void onFailure() {
-                notifySmsErrorNoDefaultSet(context, sentIntent);
+                notifySmsError(sentIntent, RESULT_NO_DEFAULT_SMS_APP);
             }
         });
     }
@@ -1305,53 +1549,20 @@
         return binder;
     }
 
-    private static void notifySmsErrorNoDefaultSet(Context context, PendingIntent pendingIntent) {
+    private static void notifySmsError(PendingIntent pendingIntent, int error) {
         if (pendingIntent != null) {
-            Intent errorMessage = new Intent();
-            errorMessage.putExtra(NO_DEFAULT_EXTRA, true);
             try {
-                pendingIntent.send(context, RESULT_ERROR_GENERIC_FAILURE, errorMessage);
+                pendingIntent.send(error);
             } catch (PendingIntent.CanceledException e) {
                 // Don't worry about it, we do not need to notify the caller if this is the case.
             }
         }
     }
 
-    private static void notifySmsErrorNoDefaultSet(Context context,
-            List<PendingIntent> pendingIntents) {
+    private static void notifySmsError(List<PendingIntent> pendingIntents, int error) {
         if (pendingIntents != null) {
             for (PendingIntent pendingIntent : pendingIntents) {
-                Intent errorMessage = new Intent();
-                errorMessage.putExtra(NO_DEFAULT_EXTRA, true);
-                try {
-                    pendingIntent.send(context, RESULT_ERROR_GENERIC_FAILURE, errorMessage);
-                } catch (PendingIntent.CanceledException e) {
-                    // Don't worry about it, we do not need to notify the caller if this is the
-                    // case.
-                }
-            }
-        }
-    }
-
-    private static void notifySmsGenericError(PendingIntent pendingIntent) {
-        if (pendingIntent != null) {
-            try {
-                pendingIntent.send(RESULT_ERROR_GENERIC_FAILURE);
-            } catch (PendingIntent.CanceledException e) {
-                // Don't worry about it, we do not need to notify the caller if this is the case.
-            }
-        }
-    }
-
-    private static void notifySmsGenericError(List<PendingIntent> pendingIntents) {
-        if (pendingIntents != null) {
-            for (PendingIntent pendingIntent : pendingIntents) {
-                try {
-                    pendingIntent.send(RESULT_ERROR_GENERIC_FAILURE);
-                } catch (PendingIntent.CanceledException e) {
-                    // Don't worry about it, we do not need to notify the caller if this is the
-                    // case.
-                }
+                notifySmsError(pendingIntent, error);
             }
         }
     }
@@ -1798,19 +2009,19 @@
     // see SmsMessage.getStatusOnIcc
 
     /** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
-    static public final int STATUS_ON_ICC_FREE      = 0;
+    public static final int STATUS_ON_ICC_FREE      = 0;
 
     /** Received and read (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
-    static public final int STATUS_ON_ICC_READ      = 1;
+    public static final int STATUS_ON_ICC_READ      = 1;
 
     /** Received and unread (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
-    static public final int STATUS_ON_ICC_UNREAD    = 3;
+    public static final int STATUS_ON_ICC_UNREAD    = 3;
 
     /** Stored and sent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
-    static public final int STATUS_ON_ICC_SENT      = 5;
+    public static final int STATUS_ON_ICC_SENT      = 5;
 
     /** Stored and unsent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
-    static public final int STATUS_ON_ICC_UNSENT    = 7;
+    public static final int STATUS_ON_ICC_UNSENT    = 7;
 
     // SMS send failure result codes
 
@@ -1846,126 +2057,263 @@
 
     /**
      * No error.
-     * @hide
      */
-    @SystemApi
-    static public final int RESULT_ERROR_NONE    = 0;
+    public static final int RESULT_ERROR_NONE    = 0;
+
     /** Generic failure cause */
-    static public final int RESULT_ERROR_GENERIC_FAILURE    = 1;
+    public static final int RESULT_ERROR_GENERIC_FAILURE    = 1;
+
     /** Failed because radio was explicitly turned off */
-    static public final int RESULT_ERROR_RADIO_OFF          = 2;
+    public static final int RESULT_ERROR_RADIO_OFF          = 2;
+
     /** Failed because no pdu provided */
-    static public final int RESULT_ERROR_NULL_PDU           = 3;
+    public static final int RESULT_ERROR_NULL_PDU           = 3;
+
     /** Failed because service is currently unavailable */
-    static public final int RESULT_ERROR_NO_SERVICE         = 4;
+    public static final int RESULT_ERROR_NO_SERVICE         = 4;
+
     /** Failed because we reached the sending queue limit. */
-    static public final int RESULT_ERROR_LIMIT_EXCEEDED     = 5;
+    public static final int RESULT_ERROR_LIMIT_EXCEEDED     = 5;
+
     /**
      * Failed because FDN is enabled.
-     * @hide
      */
-    @SystemApi
-    static public final int RESULT_ERROR_FDN_CHECK_FAILURE  = 6;
+    public static final int RESULT_ERROR_FDN_CHECK_FAILURE  = 6;
+
     /** Failed because user denied the sending of this short code. */
-    static public final int RESULT_ERROR_SHORT_CODE_NOT_ALLOWED = 7;
+    public static final int RESULT_ERROR_SHORT_CODE_NOT_ALLOWED = 7;
+
     /** Failed because the user has denied this app ever send premium short codes. */
-    static public final int RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED = 8;
+    public static final int RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED = 8;
+
     /**
      * Failed because the radio was not available
-     * @hide
      */
-    @SystemApi
-    static public final int RESULT_RADIO_NOT_AVAILABLE = 9;
+    public static final int RESULT_RADIO_NOT_AVAILABLE = 9;
+
     /**
      * Failed because of network rejection
-     * @hide
      */
-    @SystemApi
-    static public final int RESULT_NETWORK_REJECT = 10;
+    public static final int RESULT_NETWORK_REJECT = 10;
+
     /**
      * Failed because of invalid arguments
-     * @hide
      */
-    @SystemApi
-    static public final int RESULT_INVALID_ARGUMENTS = 11;
+    public static final int RESULT_INVALID_ARGUMENTS = 11;
+
     /**
      * Failed because of an invalid state
-     * @hide
      */
-    @SystemApi
-    static public final int RESULT_INVALID_STATE = 12;
+    public static final int RESULT_INVALID_STATE = 12;
+
     /**
      * Failed because there is no memory
-     * @hide
      */
-    @SystemApi
-    static public final int RESULT_NO_MEMORY = 13;
+    public static final int RESULT_NO_MEMORY = 13;
+
     /**
      * Failed because the sms format is not valid
-     * @hide
      */
-    @SystemApi
-    static public final int RESULT_INVALID_SMS_FORMAT = 14;
+    public static final int RESULT_INVALID_SMS_FORMAT = 14;
+
     /**
      * Failed because of a system error
-     * @hide
      */
-    @SystemApi
-    static public final int RESULT_SYSTEM_ERROR = 15;
+    public static final int RESULT_SYSTEM_ERROR = 15;
+
     /**
      * Failed because of a modem error
-     * @hide
      */
-    @SystemApi
-    static public final int RESULT_MODEM_ERROR = 16;
+    public static final int RESULT_MODEM_ERROR = 16;
+
     /**
      * Failed because of a network error
-     * @hide
      */
-    @SystemApi
-    static public final int RESULT_NETWORK_ERROR = 17;
+    public static final int RESULT_NETWORK_ERROR = 17;
+
     /**
      * Failed because of an encoding error
-     * @hide
      */
-    @SystemApi
-    static public final int RESULT_ENCODING_ERROR = 18;
+    public static final int RESULT_ENCODING_ERROR = 18;
+
     /**
      * Failed because of an invalid smsc address
-     * @hide
      */
-    @SystemApi
-    static public final int RESULT_INVALID_SMSC_ADDRESS = 19;
+    public static final int RESULT_INVALID_SMSC_ADDRESS = 19;
+
     /**
      * Failed because the operation is not allowed
-     * @hide
      */
-    @SystemApi
-    static public final int RESULT_OPERATION_NOT_ALLOWED = 20;
+    public static final int RESULT_OPERATION_NOT_ALLOWED = 20;
+
     /**
      * Failed because of an internal error
-     * @hide
      */
-    @SystemApi
-    static public final int RESULT_INTERNAL_ERROR = 21;
+    public static final int RESULT_INTERNAL_ERROR = 21;
+
     /**
      * Failed because there are no resources
-     * @hide
      */
-    @SystemApi
-    static public final int RESULT_NO_RESOURCES = 22;
+    public static final int RESULT_NO_RESOURCES = 22;
+
     /**
      * Failed because the operation was cancelled
-     * @hide
      */
-    @SystemApi
-    static public final int RESULT_CANCELLED = 23;
+    public static final int RESULT_CANCELLED = 23;
+
     /**
      * Failed because the request is not supported
-     * @hide
      */
-    @SystemApi
-    static public final int RESULT_REQUEST_NOT_SUPPORTED = 24;
+    public static final int RESULT_REQUEST_NOT_SUPPORTED = 24;
+
+    /**
+     * Failed sending via bluetooth because the bluetooth service is not available
+     */
+    public static final int RESULT_NO_BLUETOOTH_SERVICE = 25;
+
+    /**
+     * Failed sending via bluetooth because the bluetooth device address is invalid
+     */
+    public static final int RESULT_INVALID_BLUETOOTH_ADDRESS = 26;
+
+    /**
+     * Failed sending via bluetooth because bluetooth disconnected
+     */
+    public static final int RESULT_BLUETOOTH_DISCONNECTED = 27;
+
+    /**
+     * Failed sending because the user denied or canceled the dialog displayed for a premium
+     * shortcode sms or rate-limited sms.
+     */
+    public static final int RESULT_UNEXPECTED_EVENT_STOP_SENDING = 28;
+
+    /**
+     * Failed sending during an emergency call
+     */
+    public static final int RESULT_SMS_BLOCKED_DURING_EMERGENCY = 29;
+
+    /**
+     * Failed to send an sms retry
+     */
+    public static final int RESULT_SMS_SEND_RETRY_FAILED = 30;
+
+    /**
+     * Set by BroadcastReceiver to indicate a remote exception while handling a message.
+     */
+    public static final int RESULT_REMOTE_EXCEPTION = 31;
+
+    /**
+     * Set by BroadcastReceiver to indicate there's no default sms app.
+     */
+    public static final int RESULT_NO_DEFAULT_SMS_APP = 32;
+
+    // Radio Error results
+
+    /**
+     * The radio did not start or is resetting.
+     */
+    public static final int RESULT_RIL_RADIO_NOT_AVAILABLE = 100;
+
+    /**
+     * The radio failed to send the sms and needs to retry.
+     */
+    public static final int RESULT_RIL_SMS_SEND_FAIL_RETRY = 101;
+
+    /**
+     * The sms request was rejected by the network.
+     */
+    public static final int RESULT_RIL_NETWORK_REJECT = 102;
+
+    /**
+     * The radio returned an unexpected request for the current state.
+     */
+    public static final int RESULT_RIL_INVALID_STATE = 103;
+
+    /**
+     * The radio received invalid arguments in the request.
+     */
+    public static final int RESULT_RIL_INVALID_ARGUMENTS = 104;
+
+    /**
+     * The radio didn't have sufficient memory to process the request.
+     */
+    public static final int RESULT_RIL_NO_MEMORY = 105;
+
+    /**
+     * The radio denied the operation due to overly-frequent requests.
+     */
+    public static final int RESULT_RIL_REQUEST_RATE_LIMITED = 106;
+
+    /**
+     * The radio returned an error indicating invalid sms format.
+     */
+    public static final int RESULT_RIL_INVALID_SMS_FORMAT = 107;
+
+    /**
+     * The radio encountered a platform or system error.
+     */
+    public static final int RESULT_RIL_SYSTEM_ERR = 108;
+
+    /**
+     * The SMS message was not encoded properly.
+     */
+    public static final int RESULT_RIL_ENCODING_ERR = 109;
+
+    /**
+     * The specified SMSC address was invalid.
+     */
+    public static final int RESULT_RIL_INVALID_SMSC_ADDRESS = 110;
+
+    /**
+     * The vendor RIL received an unexpected or incorrect response.
+     */
+    public static final int RESULT_RIL_MODEM_ERR = 111;
+
+    /**
+     * The radio received an error from the network.
+     */
+    public static final int RESULT_RIL_NETWORK_ERR = 112;
+
+    /**
+     * The modem encountered an unexpected error scenario while handling the request.
+     */
+    public static final int RESULT_RIL_INTERNAL_ERR = 113;
+
+    /**
+     * The request was not supported by the radio.
+     */
+    public static final int RESULT_RIL_REQUEST_NOT_SUPPORTED = 114;
+
+    /**
+     * The radio cannot process the request in the current modem state.
+     */
+    public static final int RESULT_RIL_INVALID_MODEM_STATE = 115;
+
+    /**
+     * The network is not ready to perform the request.
+     */
+    public static final int RESULT_RIL_NETWORK_NOT_READY = 116;
+
+    /**
+     * The radio reports the request is not allowed.
+     */
+    public static final int RESULT_RIL_OPERATION_NOT_ALLOWED = 117;
+
+    /**
+     * There are not sufficient resources to process the request.
+     */
+    public static final int RESULT_RIL_NO_RESOURCES = 118;
+
+    /**
+     * The request has been cancelled.
+     */
+    public static final int RESULT_RIL_CANCELLED = 119;
+
+    /**
+     * The radio failed to set the location where the CDMA subscription
+     * can be retrieved because the SIM or RUIM is absent.
+     */
+    public static final int RESULT_RIL_SIM_ABSENT = 120;
 
     /**
      * Send an MMS message
@@ -2321,4 +2669,74 @@
         }
         return SmsManager.SMS_CATEGORY_NOT_SHORT_CODE;
     }
+
+    /**
+     * Gets the SMSC address from (U)SIM.
+     *
+     * <p class="note"><strong>Note:</strong> Using this method requires that your app is the
+     * default SMS application, or READ_PRIVILEGED_PHONE_STATE permission, or has the carrier
+     * privileges.</p>
+     *
+     * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation
+     * dialog. If this method is called on a device that has multiple active subscriptions, this
+     * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
+     * default subscription is defined, the subscription ID associated with this method will be
+     * INVALID, which will result in the operation being completed on the subscription associated
+     * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the operation
+     * is performed on the correct subscription.
+     * </p>
+     *
+     * @return the SMSC address string, null if failed.
+     */
+    @SuppressAutoDoc // for carrier privileges and default SMS application.
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @Nullable
+    public String getSmscAddress() {
+        String smsc = null;
+
+        try {
+            ISms iSms = getISmsService();
+            if (iSms != null) {
+                smsc = iSms.getSmscAddressFromIccEfForSubscriber(
+                        getSubscriptionId(), ActivityThread.currentPackageName());
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+        return smsc;
+    }
+
+    /**
+     * Sets the SMSC address on (U)SIM.
+     *
+     * <p class="note"><strong>Note:</strong> Using this method requires that your app is the
+     * default SMS application, or has {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+     * permission, or has the carrier privileges.</p>
+     *
+     * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation
+     * dialog. If this method is called on a device that has multiple active subscriptions, this
+     * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
+     * default subscription is defined, the subscription ID associated with this method will be
+     * INVALID, which will result in the operation being completed on the subscription associated
+     * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the operation
+     * is performed on the correct subscription.
+     * </p>
+     *
+     * @param smsc the SMSC address string.
+     * @return true for success, false otherwise.
+     */
+    @SuppressAutoDoc // for carrier privileges and default SMS application.
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public boolean setSmscAddress(@NonNull String smsc) {
+        try {
+            ISms iSms = getISmsService();
+            if (iSms != null) {
+                return iSms.setSmscAddressOnIccEfForSubscriber(
+                        smsc, getSubscriptionId(), ActivityThread.currentPackageName());
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+        return false;
+    }
 }
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 8425ec1..b5e91d0 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -49,7 +49,6 @@
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.Looper;
-import android.os.Message;
 import android.os.ParcelUuid;
 import android.os.Process;
 import android.os.RemoteException;
@@ -2053,13 +2052,13 @@
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static boolean isValidSlotIndex(int slotIndex) {
-        return slotIndex >= 0 && slotIndex < TelephonyManager.getDefault().getSupportedModemCount();
+        return slotIndex >= 0 && slotIndex < TelephonyManager.getDefault().getActiveModemCount();
     }
 
     /** @hide */
     @UnsupportedAppUsage
     public static boolean isValidPhoneId(int phoneId) {
-        return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getSupportedModemCount();
+        return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getActiveModemCount();
     }
 
     /** @hide */
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 06a7370..0c663f8 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -110,6 +110,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Objects;
 import java.util.UUID;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
@@ -197,12 +198,29 @@
     /** @hide */
     static public final int OTASP_SIM_UNPROVISIONED = 5;
 
-    /** @hide */
+    /**
+     * Used in carrier Wi-Fi for IMSI + IMPI encryption, this indicates a public key that's
+     * available for use in ePDG links.
+     *
+     * @hide
+     */
+    @SystemApi
     static public final int KEY_TYPE_EPDG = 1;
 
-    /** @hide */
+    /**
+     * Used in carrier Wi-Fi for IMSI + IMPI encryption, this indicates a public key that's
+     * available for use in WLAN links.
+     *
+     * @hide
+     */
+    @SystemApi
     static public final int KEY_TYPE_WLAN = 2;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"KEY_TYPE_"}, value = {KEY_TYPE_EPDG, KEY_TYPE_WLAN})
+    public @interface KeyType {}
+
     /**
      * No Single Radio Voice Call Continuity (SRVCC) handover is active.
      * See TS 23.216 for more information.
@@ -308,7 +326,11 @@
         mSubId = subId;
         Context appContext = context.getApplicationContext();
         if (appContext != null) {
-            mContext = appContext;
+            if (Objects.equals(context.getFeatureId(), appContext.getFeatureId())) {
+                mContext = appContext;
+            } else {
+                mContext = appContext.createFeatureContext(context.getFeatureId());
+            }
         } else {
             mContext = context;
         }
@@ -343,6 +365,16 @@
         return ActivityThread.currentOpPackageName();
     }
 
+    private String getFeatureId() {
+        // For legacy reasons the TelephonyManager has API for getting
+        // a static instance with no context set preventing us from
+        // getting the feature Id.
+        if (mContext != null) {
+            return mContext.getFeatureId();
+        }
+        return null;
+    }
+
     private boolean isSystemProcess() {
         return Process.myUid() == Process.SYSTEM_UID;
     }
@@ -424,18 +456,8 @@
      * {@link #getActiveModemCount} returns 1 while this API returns 2.
      */
     public @ModemCount int getSupportedModemCount() {
-        // TODO: b/139642279 when turning on this feature, remove dependency of
-        // PROPERTY_REBOOT_REQUIRED_ON_MODEM_CHANGE and always return result based on
-        // PROPERTY_MAX_ACTIVE_MODEMS.
-        String rebootRequired = SystemProperties.get(
-                TelephonyProperties.PROPERTY_REBOOT_REQUIRED_ON_MODEM_CHANGE);
-        if (rebootRequired.equals("false")) {
-            // If no reboot is required, return max possible active modems.
-            return SystemProperties.getInt(
-                    TelephonyProperties.PROPERTY_MAX_ACTIVE_MODEMS, getPhoneCount());
-        } else {
-            return getPhoneCount();
-        }
+        return SystemProperties.getInt(TelephonyProperties.PROPERTY_MAX_ACTIVE_MODEMS,
+                getActiveModemCount());
     }
 
     /** {@hide} */
@@ -1883,7 +1905,12 @@
         if (telephony == null) return null;
 
         try {
-            return telephony.getMeidForSlot(slotIndex, getOpPackageName());
+            String meid = telephony.getMeidForSlot(slotIndex, getOpPackageName());
+            if (TextUtils.isEmpty(meid)) {
+                Log.d(TAG, "getMeid: return null because MEID is not available");
+                return null;
+            }
+            return meid;
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -2012,7 +2039,8 @@
                 return null;
             }
 
-            Bundle bundle = telephony.getCellLocation(mContext.getOpPackageName());
+            Bundle bundle = telephony.getCellLocation(mContext.getOpPackageName(),
+                    mContext.getFeatureId());
             if (bundle == null || bundle.isEmpty()) {
                 Rlog.d(TAG, "getCellLocation returning null because CellLocation is unavailable");
                 return null;
@@ -2100,7 +2128,8 @@
             ITelephony telephony = getITelephony();
             if (telephony == null)
                 return null;
-            return telephony.getNeighboringCellInfo(mContext.getOpPackageName());
+            return telephony.getNeighboringCellInfo(mContext.getOpPackageName(),
+                    mContext.getFeatureId());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -3879,25 +3908,27 @@
     }
 
     /**
-     * Returns Carrier specific information that will be used to encrypt the IMSI and IMPI.
-     * This includes the public key and the key identifier. For multi-sim devices, if no subId
-     * has been specified, we will return the value for the dafault data sim.
-     * Return null if it is unavailable.
+     * Returns carrier specific information that will be used to encrypt the IMSI and IMPI,
+     * including the public key and the key identifier; or {@code null} if not available.
      * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
-     * @param keyType whether the key is being used for wlan or epdg. Valid key types are
-     *        {@link TelephonyManager#KEY_TYPE_EPDG} or
-     *        {@link TelephonyManager#KEY_TYPE_WLAN}.
+     * For a multi-sim device, the dafault data sim is used if not specified.
+     * <p>
+     * Requires Permission: READ_PRIVILEGED_PHONE_STATE.
+     *
+     * @param keyType whether the key is being used for EPDG or WLAN. Valid values are
+     *        {@link #KEY_TYPE_EPDG} or {@link #KEY_TYPE_WLAN}.
      * @return ImsiEncryptionInfo Carrier specific information that will be used to encrypt the
      *         IMSI and IMPI. This includes the public key and the key identifier. This information
-     *         will be stored in the device keystore. The system will return a null when no key was
-     *         found, and the carrier does not require a key. The system will throw
-     *         IllegalArgumentException when an invalid key is sent or when key is required but
+     *         will be stored in the device keystore. {@code null} will be returned when no key is
+     *         found, and the carrier does not require a key.
+     * @throws IllegalArgumentException when an invalid key is found or when key is required but
      *         not found.
      * @hide
      */
-    public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType) {
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @SystemApi
+    @Nullable
+    public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(@KeyType int keyType) {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null) {
@@ -3925,14 +3956,21 @@
     }
 
     /**
-     * Resets the Carrier Keys in the database. This involves 2 steps:
+     * Resets the carrier keys used to encrypt the IMSI and IMPI.
+     * <p>
+     * This involves 2 steps:
      *  1. Delete the keys from the database.
      *  2. Send an intent to download new Certificates.
      * <p>
-     * Requires Permission:
-     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * For a multi-sim device, the dafault data sim is used if not specified.
+     * <p>
+     * Requires Permission: MODIFY_PHONE_STATE.
+     *
+     * @see #getCarrierInfoForImsiEncryption
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @SystemApi
     public void resetCarrierKeysForImsiEncryption() {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
@@ -3959,7 +3997,7 @@
      * @return true if the digit at position keyType is 1, else false.
      * @hide
      */
-    private static boolean isKeyEnabled(int keyAvailability, int keyType) {
+    private static boolean isKeyEnabled(int keyAvailability, @KeyType int keyType) {
         int returnValue = (keyAvailability >> (keyType - 1)) & 1;
         return (returnValue == 1) ? true : false;
     }
@@ -3968,7 +4006,7 @@
      * If Carrier requires Imsi to be encrypted.
      * @hide
      */
-    private boolean isImsiEncryptionRequired(int subId, int keyType) {
+    private boolean isImsiEncryptionRequired(int subId, @KeyType int keyType) {
         CarrierConfigManager configManager =
                 (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
         if (configManager == null) {
@@ -5493,8 +5531,7 @@
             ITelephony telephony = getITelephony();
             if (telephony == null)
                 return null;
-            return telephony.getAllCellInfo(
-                    getOpPackageName());
+            return telephony.getAllCellInfo(getOpPackageName(), getFeatureId());
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -5586,7 +5623,7 @@
                                             errorCode,
                                             createThrowableByClassName(exceptionName, message))));
                         }
-                    }, getOpPackageName());
+                    }, getOpPackageName(), getFeatureId());
         } catch (RemoteException ex) {
         }
     }
@@ -5628,7 +5665,7 @@
                                             errorCode,
                                             createThrowableByClassName(exceptionName, message))));
                         }
-                    }, getOpPackageName(), workSource);
+                    }, getOpPackageName(), getFeatureId(), workSource);
         } catch (RemoteException ex) {
         }
     }
@@ -7452,7 +7489,8 @@
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                return telephony.getCellNetworkScanResults(getSubId(), getOpPackageName());
+                return telephony.getCellNetworkScanResults(getSubId(), getOpPackageName(),
+                        getFeatureId());
             }
         } catch (RemoteException ex) {
             Rlog.e(TAG, "getAvailableNetworks RemoteException", ex);
@@ -7507,7 +7545,7 @@
             }
         }
         return mTelephonyScanManager.requestNetworkScan(getSubId(), request, executor, callback,
-                getOpPackageName());
+                getOpPackageName(), getFeatureId());
     }
 
     /**
@@ -9503,24 +9541,38 @@
         return returnValue;
     }
 
-    private int getSubIdForPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) {
+    /**
+     * Returns the subscription ID for the given phone account handle.
+     *
+     * @param phoneAccountHandle the phone account handle for outgoing calls
+     * @return subscription ID for the given phone account handle; or
+     *         {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}
+     *         if not available; or throw a SecurityException if the caller doesn't have the
+     *         permission.
+     */
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    public int getSubIdForPhoneAccountHandle(@NonNull PhoneAccountHandle phoneAccountHandle) {
         int retval = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
         try {
-            ITelecomService service = getTelecomService();
+            ITelephony service = getITelephony();
             if (service != null) {
-                retval = getSubIdForPhoneAccount(service.getPhoneAccount(phoneAccountHandle));
+                retval = service.getSubIdForPhoneAccountHandle(
+                        phoneAccountHandle, mContext.getOpPackageName());
             }
-        } catch (RemoteException e) {
+        } catch (RemoteException ex) {
+            Log.e(TAG, "getSubIdForPhoneAccountHandle RemoteException", ex);
+            ex.rethrowAsRuntimeException();
         }
-
         return retval;
     }
 
     /**
-     * Resets telephony manager settings back to factory defaults.
+     * Resets Telephony and IMS settings back to factory defaults.
      *
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.CONNECTIVITY_INTERNAL)
     public void factoryReset(int subId) {
         try {
             Log.d(TAG, "factoryReset: subId=" + subId);
@@ -9624,7 +9676,8 @@
         try {
             ITelephony service = getITelephony();
             if (service != null) {
-                return service.getServiceStateForSubscriber(subId, getOpPackageName());
+                return service.getServiceStateForSubscriber(subId, getOpPackageName(),
+                        getFeatureId());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#getServiceStateForSubscriber", e);
@@ -10237,11 +10290,13 @@
 
     /**
      * Action set from carrier signalling broadcast receivers to enable/disable radio
-     * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
+     * Permissions {@link android.Manifest.permission.MODIFY_PHONE_STATE} is required.
      * @param subId the subscription ID that this action applies to.
      * @param enabled control enable or disable radio.
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void carrierActionSetRadioEnabled(int subId, boolean enabled) {
         try {
             ITelephony service = getITelephony();
@@ -10256,11 +10311,13 @@
     /**
      * Action set from carrier signalling broadcast receivers to start/stop reporting default
      * network available events
-     * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
+     * Permissions {@link android.Manifest.permission.MODIFY_PHONE_STATE} is required.
      * @param subId the subscription ID that this action applies to.
      * @param report control start/stop reporting network status.
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void carrierActionReportDefaultNetworkStatus(int subId, boolean report) {
         try {
             ITelephony service = getITelephony();
@@ -10274,10 +10331,12 @@
 
     /**
      * Action set from carrier signalling broadcast receivers to reset all carrier actions
-     * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
+     * Permissions {@link android.Manifest.permission.MODIFY_PHONE_STATE} is required.
      * @param subId the subscription ID that this action applies to.
      * @hide
      */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void carrierActionResetAll(int subId) {
         try {
             ITelephony service = getITelephony();
@@ -10873,6 +10932,16 @@
     }
 
     /**
+     * Broadcast intent action for Ota emergency number database installation complete.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @SystemApi
+    public static final String ACTION_OTA_EMERGENCY_NUMBER_DB_INSTALLED =
+            "android.telephony.action.OTA_EMERGENCY_NUMBER_DB_INSTALLED";
+
+    /**
      * Returns whether {@link TelephonyManager#ACTION_EMERGENCY_ASSISTANCE emergency assistance} is
      * available on the device.
      * <p>
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index 9ff8515..96b6db7 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -18,6 +18,7 @@
 
 import static com.android.internal.util.Preconditions.checkNotNull;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.os.Binder;
 import android.os.Bundle;
@@ -195,18 +196,21 @@
      *
      * @param request Contains all the RAT with bands/channels that need to be scanned.
      * @param callback Returns network scan results or errors.
+     * @param callingPackage The package name of the caller
+     * @param callingFeatureId The feature id inside of the calling package
      * @return A NetworkScan obj which contains a callback which can stop the scan.
      * @hide
      */
     public NetworkScan requestNetworkScan(int subId,
             NetworkScanRequest request, Executor executor, NetworkScanCallback callback,
-            String callingPackage) {
+            String callingPackage, @Nullable String callingFeatureId) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 synchronized (mScanInfo) {
                     int scanId = telephony.requestNetworkScan(
-                            subId, request, mMessenger, new Binder(), callingPackage);
+                            subId, request, mMessenger, new Binder(), callingPackage,
+                            callingFeatureId);
                     if (scanId == INVALID_SCAN_ID) {
                         Rlog.e(TAG, "Failed to initiate network scan");
                         return null;
diff --git a/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.aidl b/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.aidl
new file mode 100644
index 0000000..a648a0e
--- /dev/null
+++ b/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/** @hide */
+package android.telephony.cdma;
+
+parcelable CdmaSmsCbProgramData;
+
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 2161dcb..a5d6266 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1191,7 +1191,7 @@
             && !other.canHandleType(TYPE_DUN)
             && Objects.equals(this.mApnName, other.mApnName)
             && !typeSameAny(this, other)
-            && xorEquals(this.mProxyAddress, other.mProxyAddress)
+            && xorEqualsString(this.mProxyAddress, other.mProxyAddress)
             && xorEqualsInt(this.mProxyPort, other.mProxyPort)
             && xorEquals(this.mProtocol, other.mProtocol)
             && xorEquals(this.mRoamingProtocol, other.mRoamingProtocol)
@@ -1200,7 +1200,7 @@
             && Objects.equals(this.mMvnoType, other.mMvnoType)
             && Objects.equals(this.mMvnoMatchData, other.mMvnoMatchData)
             && xorEquals(this.mMmsc, other.mMmsc)
-            && xorEquals(this.mMmsProxyAddress, other.mMmsProxyAddress)
+            && xorEqualsString(this.mMmsProxyAddress, other.mMmsProxyAddress)
             && xorEqualsInt(this.mMmsProxyPort, other.mMmsProxyPort))
             && Objects.equals(this.mNetworkTypeBitmask, other.mNetworkTypeBitmask)
             && Objects.equals(mApnSetId, other.mApnSetId)
@@ -1213,6 +1213,11 @@
         return first == null || second == null || first.equals(second);
     }
 
+    // Equal or one is null.
+    private boolean xorEqualsString(String first, String second) {
+        return TextUtils.isEmpty(first) || TextUtils.isEmpty(second) || first.equals(second);
+    }
+
     // Equal or one is not specified.
     private boolean xorEqualsInt(int first, int second) {
         return first == UNSPECIFIED_INT || second == UNSPECIFIED_INT
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 5a90cb1..0025c7a 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -830,7 +830,7 @@
      * @param callbackIntent a PendingIntent to launch when the operation completes.
      *
      * @deprecated From R, callers should specify a flag for specific set of subscriptions to erase
-     * and use @link{eraseSubscriptionsWithOptions} instead
+     * and use {@link #eraseSubscriptionsWithOptions(int, PendingIntent)} instead
      *
      * @hide
      */
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 2fad847..7cafa1e 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -25,30 +25,26 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.Context;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.net.Uri;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
 import android.telephony.AccessNetworkConstants;
+import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
-import android.telephony.ims.aidl.IImsRegistrationCallback;
 import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
-import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.IIntegerConsumer;
 import com.android.internal.telephony.ITelephony;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.HashMap;
-import java.util.Map;
 import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 /**
  * A manager for the MmTel (Multimedia Telephony) feature of an IMS network, given an associated
@@ -62,9 +58,7 @@
  * @hide
  */
 @SystemApi
-public class ImsMmTelManager {
-
-    private static final String TAG = "ImsMmTelManager";
+public class ImsMmTelManager implements RegistrationManager {
 
     /**
      * @hide
@@ -97,94 +91,18 @@
      * Callback class for receiving IMS network Registration callback events.
      * @see #registerImsRegistrationCallback(Executor, RegistrationCallback) (RegistrationCallback)
      * @see #unregisterImsRegistrationCallback(RegistrationCallback)
+     * @deprecated Use {@link RegistrationManager.RegistrationCallback} instead.
      */
-    public static class RegistrationCallback {
-
-        private static class RegistrationBinder extends IImsRegistrationCallback.Stub {
-
-            // Translate ImsRegistrationImplBase API to new AccessNetworkConstant because WLAN
-            // and WWAN are more accurate constants.
-            private static final Map<Integer, Integer> IMS_REG_TO_ACCESS_TYPE_MAP =
-                    new HashMap<Integer, Integer>() {{
-                        // Map NONE to -1 to make sure that we handle the REGISTRATION_TECH_NONE
-                        // case, since it is defined.
-                        put(ImsRegistrationImplBase.REGISTRATION_TECH_NONE, -1);
-                        put(ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
-                                AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
-                        put(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
-                                AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
-                    }};
-
-            private final RegistrationCallback mLocalCallback;
-            private Executor mExecutor;
-
-            RegistrationBinder(RegistrationCallback localCallback) {
-                mLocalCallback = localCallback;
-            }
-
-            @Override
-            public void onRegistered(int imsRadioTech) {
-                if (mLocalCallback == null) return;
-
-                Binder.withCleanCallingIdentity(() -> mExecutor.execute(() ->
-                        mLocalCallback.onRegistered(getAccessType(imsRadioTech))));
-            }
-
-            @Override
-            public void onRegistering(int imsRadioTech) {
-                if (mLocalCallback == null) return;
-
-                Binder.withCleanCallingIdentity(() -> mExecutor.execute(() ->
-                        mLocalCallback.onRegistering(getAccessType(imsRadioTech))));
-            }
-
-            @Override
-            public void onDeregistered(ImsReasonInfo info) {
-                if (mLocalCallback == null) return;
-
-                Binder.withCleanCallingIdentity(() ->
-                        mExecutor.execute(() -> mLocalCallback.onUnregistered(info)));
-            }
-
-            @Override
-            public void onTechnologyChangeFailed(int imsRadioTech, ImsReasonInfo info) {
-                if (mLocalCallback == null) return;
-
-                Binder.withCleanCallingIdentity(() ->
-                        mExecutor.execute(() -> mLocalCallback.onTechnologyChangeFailed(
-                                getAccessType(imsRadioTech), info)));
-            }
-
-            @Override
-            public void onSubscriberAssociatedUriChanged(Uri[] uris) {
-                if (mLocalCallback == null) return;
-
-                Binder.withCleanCallingIdentity(() ->
-                        mExecutor.execute(() ->
-                                mLocalCallback.onSubscriberAssociatedUriChanged(uris)));
-            }
-
-            private void setExecutor(Executor executor) {
-                mExecutor = executor;
-            }
-
-            private static int getAccessType(int regType) {
-                if (!IMS_REG_TO_ACCESS_TYPE_MAP.containsKey(regType)) {
-                    Log.w("ImsMmTelManager", "RegistrationBinder - invalid regType returned: "
-                            + regType);
-                    return -1;
-                }
-                return IMS_REG_TO_ACCESS_TYPE_MAP.get(regType);
-            }
-        }
-
-        private final RegistrationBinder mBinder = new RegistrationBinder(this);
+    // Do not add to this class, add to RegistrationManager.RegistrationCallback instead.
+    @Deprecated
+    public static class RegistrationCallback extends RegistrationManager.RegistrationCallback {
 
         /**
          * Notifies the framework when the IMS Provider is registered to the IMS network.
          *
          * @param imsTransportType the radio access technology.
          */
+        @Override
         public void onRegistered(@AccessNetworkConstants.TransportType int imsTransportType) {
         }
 
@@ -193,6 +111,7 @@
          *
          * @param imsTransportType the radio access technology.
          */
+        @Override
         public void onRegistering(@AccessNetworkConstants.TransportType int imsTransportType) {
         }
 
@@ -201,6 +120,7 @@
          *
          * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
          */
+        @Override
         public void onUnregistered(@Nullable ImsReasonInfo info) {
         }
 
@@ -210,33 +130,11 @@
          * @param imsTransportType The transport type that has failed to handover registration to.
          * @param info A {@link ImsReasonInfo} that identifies the reason for failure.
          */
+        @Override
         public void onTechnologyChangeFailed(
                 @AccessNetworkConstants.TransportType int imsTransportType,
                 @Nullable ImsReasonInfo info) {
         }
-
-        /**
-         * Returns a list of subscriber {@link Uri}s associated with this IMS subscription when
-         * it changes. Per RFC3455, an associated URI is a URI that the service provider has
-         * allocated to a user for their own usage. A user's phone number is typically one of the
-         * associated URIs.
-         * @param uris new array of subscriber {@link Uri}s that are associated with this IMS
-         *         subscription.
-         * @hide
-         */
-        public void onSubscriberAssociatedUriChanged(@Nullable Uri[] uris) {
-        }
-
-        /**@hide*/
-        public final IImsRegistrationCallback getBinder() {
-            return mBinder;
-        }
-
-        /**@hide*/
-        //Only exposed as public for compatibility with deprecated ImsManager APIs.
-        public void setExecutor(Executor executor) {
-            mBinder.setExecutor(executor);
-        }
     }
 
     /**
@@ -311,7 +209,7 @@
         }
     }
 
-    private int mSubId;
+    private final int mSubId;
 
     /**
      * Create an instance of {@link ImsMmTelManager} for the subscription id specified.
@@ -356,7 +254,10 @@
      * the {@link ImsService} associated with the subscription is not available. This can happen if
      * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
      * reason.
+     * @deprecated Use {@link #registerImsRegistrationCallback(
+     * RegistrationManager.RegistrationCallback, Executor)} instead.
      */
+    @Deprecated
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull RegistrationCallback c) throws ImsException {
@@ -366,10 +267,6 @@
         if (executor == null) {
             throw new IllegalArgumentException("Must include a non-null Executor.");
         }
-        if (!isImsAvailableOnDevice()) {
-            throw new ImsException("IMS not available on device.",
-                    ImsException.CODE_ERROR_UNSUPPORTED_OPERATION);
-        }
         c.setExecutor(executor);
         try {
             getITelephony().registerImsRegistrationCallback(mSubId, c.getBinder());
@@ -378,13 +275,35 @@
                 // Rethrow as runtime error to keep API compatible.
                 throw new IllegalArgumentException(e.getMessage());
             } else {
-                throw new RuntimeException(e.getMessage());
+                throw new ImsException(e.getMessage(), e.errorCode);
             }
         } catch (RemoteException | IllegalStateException e) {
             throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
     }
 
+    /**{@inheritDoc}*/
+    @Override
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public void registerImsRegistrationCallback(
+            @NonNull RegistrationManager.RegistrationCallback c,
+            @NonNull @CallbackExecutor Executor executor) throws ImsException {
+        if (c == null) {
+            throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException("Must include a non-null Executor.");
+        }
+        c.setExecutor(executor);
+        try {
+            getITelephony().registerImsRegistrationCallback(mSubId, c.getBinder());
+        } catch (ServiceSpecificException e) {
+            throw new ImsException(e.getMessage(), e.errorCode);
+        } catch (RemoteException | IllegalStateException e) {
+            throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+        }
+    }
+
     /**
      * Removes an existing {@link RegistrationCallback}.
      *
@@ -395,7 +314,10 @@
      * @param c The {@link RegistrationCallback} to be removed.
      * @see SubscriptionManager.OnSubscriptionsChangedListener
      * @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
+     * @deprecated Use {@link #unregisterImsRegistrationCallback(
+     * RegistrationManager.RegistrationCallback)}.
      */
+    @Deprecated
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c) {
         if (c == null) {
@@ -408,6 +330,69 @@
         }
     }
 
+    /**{@inheritDoc}*/
+    @Override
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public void unregisterImsRegistrationCallback(
+            @NonNull RegistrationManager.RegistrationCallback c) {
+        if (c == null) {
+            throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
+        }
+        try {
+            getITelephony().unregisterImsRegistrationCallback(mSubId, c.getBinder());
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /**{@inheritDoc}*/
+    @Override
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public void getRegistrationState(@NonNull @ImsRegistrationState Consumer<Integer> stateCallback,
+            @NonNull @CallbackExecutor Executor executor) {
+        if (stateCallback == null) {
+            throw new IllegalArgumentException("Must include a non-null callback.");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException("Must include a non-null Executor.");
+        }
+        try {
+            getITelephony().getImsMmTelRegistrationState(mSubId, new IIntegerConsumer.Stub() {
+                @Override
+                public void accept(int result) {
+                    executor.execute(() -> stateCallback.accept(result));
+                }
+            });
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /**{@inheritDoc}*/
+    @Override
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public void getRegistrationTransportType(
+            @NonNull @AccessNetworkConstants.TransportType Consumer<Integer> transportTypeCallback,
+            @NonNull @CallbackExecutor Executor executor) {
+        if (transportTypeCallback == null) {
+            throw new IllegalArgumentException("Must include a non-null callback.");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException("Must include a non-null Executor.");
+        }
+        try {
+            getITelephony().getImsMmTelRegistrationTransportType(mSubId,
+                    new IIntegerConsumer.Stub() {
+                        @Override
+                        public void accept(int result) {
+                            executor.execute(() -> transportTypeCallback.accept(result));
+                        }
+                    });
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
     /**
      * Registers a {@link CapabilityCallback} with the system, which will provide MmTel service
      * availability updates for the subscription specified in
@@ -416,7 +401,7 @@
      *
      * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
      * subscription changed events and call
-     * {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
+     * {@link #unregisterMmTelCapabilityCallback(CapabilityCallback)} to clean up.
      *
      * When the callback is registered, it will initiate the callback c to be called with the
      * current capabilities.
@@ -441,10 +426,6 @@
         if (executor == null) {
             throw new IllegalArgumentException("Must include a non-null Executor.");
         }
-        if (!isImsAvailableOnDevice()) {
-            throw new ImsException("IMS not available on device.",
-                    ImsException.CODE_ERROR_UNSUPPORTED_OPERATION);
-        }
         c.setExecutor(executor);
         try {
             getITelephony().registerMmTelCapabilityCallback(mSubId, c.getBinder());
@@ -453,7 +434,7 @@
                 // Rethrow as runtime error to keep API compatible.
                 throw new IllegalArgumentException(e.getMessage());
             } else {
-                throw new RuntimeException(e.getMessage());
+                throw new ImsException(e.getMessage(), e.errorCode);
             }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
@@ -618,6 +599,46 @@
     }
 
     /**
+     * Query whether or not the requested MmTel capability is supported by the carrier on the
+     * specified network transport.
+     * <p>
+     * This is a configuration option and does not change. The only time this may change is if a
+     * new IMS configuration is loaded when there is a
+     * {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} broadcast for this subscription.
+     * @param capability The capability that is being queried for support on the carrier network.
+     * @param transportType The transport type of the capability to check support for.
+     * @param callback A consumer containing a Boolean result specifying whether or not the
+     *                 capability is supported on this carrier network for the transport specified.
+     * @param executor The executor that the callback will be called with.
+     * @throws ImsException if the subscription is no longer valid or the IMS service is not
+     * available.
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public void isSupported(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
+            @AccessNetworkConstants.TransportType int transportType,
+            @NonNull Consumer<Boolean> callback,
+            @NonNull @CallbackExecutor Executor executor) throws ImsException {
+        if (callback == null) {
+            throw new IllegalArgumentException("Must include a non-null Consumer.");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException("Must include a non-null Executor.");
+        }
+        try {
+            getITelephony().isMmTelCapabilitySupported(mSubId, new IIntegerConsumer.Stub() {
+                @Override
+                public void accept(int result) {
+                    executor.execute(() -> callback.accept(result == 1));
+                }
+            }, capability, transportType);
+        } catch (ServiceSpecificException sse) {
+            throw new ImsException(sse.getMessage(), sse.errorCode);
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
+        }
+    }
+
+    /**
      * The user's setting for whether or not they have enabled the "Video Calling" setting.
      *
      * @throws IllegalArgumentException if the subscription associated with this operation is not
@@ -940,7 +961,7 @@
      * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    boolean isTtyOverVolteEnabled() {
+    public boolean isTtyOverVolteEnabled() {
         try {
             return getITelephony().isTtyOverVolteEnabled(mSubId);
         } catch (ServiceSpecificException e) {
@@ -955,20 +976,39 @@
         }
     }
 
-    private static boolean isImsAvailableOnDevice() {
-        IPackageManager pm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
-        if (pm == null) {
-            // For some reason package manger is not available.. This will fail internally anyways,
-            // so do not throw error and allow.
-            return true;
+    /**
+     * Get the status of the MmTel Feature registered on this subscription.
+     * @param callback A callback containing an Integer describing the current state of the
+     *                 MmTel feature, Which will be one of the following:
+     *                 {@link ImsFeature#STATE_UNAVAILABLE},
+     *                {@link ImsFeature#STATE_INITIALIZING},
+     *                {@link ImsFeature#STATE_READY}. Will be called using the executor
+     *                 specified when the service state has been retrieved from the IMS service.
+     * @param executor The executor that will be used to call the callback.
+     * @throws ImsException if the IMS service associated with this subscription is not available or
+     * the IMS service is not available.
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public void getFeatureState(@NonNull @ImsFeature.ImsState Consumer<Integer> callback,
+            @NonNull @CallbackExecutor Executor executor) throws ImsException {
+        if (callback == null) {
+            throw new IllegalArgumentException("Must include a non-null Consumer.");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException("Must include a non-null Executor.");
         }
         try {
-            return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS, 0);
+            getITelephony().getImsMmTelFeatureState(mSubId, new IIntegerConsumer.Stub() {
+                @Override
+                public void accept(int result) {
+                    executor.execute(() -> callback.accept(result));
+                }
+            });
+        } catch (ServiceSpecificException sse) {
+            throw new ImsException(sse.getMessage(), sse.errorCode);
         } catch (RemoteException e) {
-            // For some reason package manger is not available.. This will fail internally anyways,
-            // so do not throw error and allow.
+            e.rethrowAsRuntimeException();
         }
-        return true;
     }
 
     private static ITelephony getITelephony() {
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index 3c343dd..25bd1ca 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -22,12 +22,14 @@
 import android.annotation.RequiresPermission;
 import android.content.Context;
 import android.os.Binder;
+import android.telephony.AccessNetworkConstants;
 import android.telephony.SubscriptionManager;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
 import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.feature.RcsFeature;
 
 import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 /**
  * Manager for interfacing with the framework RCS services, including the User Capability Exchange
@@ -36,7 +38,7 @@
  * Use {@link #createForSubscriptionId(Context, int)} to create an instance of this manager.
  * @hide
  */
-public class ImsRcsManager {
+public class ImsRcsManager implements RegistrationManager {
 
     /**
      * Receives RCS availability status updates from the ImsService.
@@ -136,6 +138,64 @@
         mSubId = subId;
     }
 
+    /**{@inheritDoc}*/
+    @Override
+    public void registerImsRegistrationCallback(
+            @NonNull RegistrationManager.RegistrationCallback c,
+            @NonNull @CallbackExecutor Executor executor)
+            throws ImsException {
+        if (c == null) {
+            throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException("Must include a non-null Executor.");
+        }
+        c.setExecutor(executor);
+        throw new UnsupportedOperationException("registerImsRegistrationCallback is not"
+                + "supported.");
+    }
+
+    /**{@inheritDoc}*/
+    @Override
+    public void unregisterImsRegistrationCallback(
+            @NonNull RegistrationManager.RegistrationCallback c) {
+        if (c == null) {
+            throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
+        }
+        throw new UnsupportedOperationException("unregisterImsRegistrationCallback is not"
+                + "supported.");
+    }
+
+    /**{@inheritDoc}*/
+    @Override
+    public void getRegistrationState(@NonNull @ImsRegistrationState Consumer<Integer> stateCallback,
+            @NonNull @CallbackExecutor Executor executor) {
+        if (stateCallback == null) {
+            throw new IllegalArgumentException("Must include a non-null stateCallback.");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException("Must include a non-null Executor.");
+        }
+        throw new UnsupportedOperationException("getRegistrationState is not"
+                + "supported.");
+    }
+
+    /**{@inheritDoc}*/
+    @Override
+    public void getRegistrationTransportType(
+            @NonNull @AccessNetworkConstants.TransportType Consumer<Integer> transportTypeCallback,
+            @NonNull @CallbackExecutor Executor executor) {
+        if (transportTypeCallback == null) {
+            throw new IllegalArgumentException("Must include a non-null transportTypeCallback.");
+        }
+        if (executor == null) {
+            throw new IllegalArgumentException("Must include a non-null Executor.");
+        }
+        throw new UnsupportedOperationException("getRegistrationTransportType is not"
+                + "supported.");
+    }
+
+
     /**
      * Registers an {@link AvailabilityCallback} with the system, which will provide RCS
      * availability updates for the subscription specified.
diff --git a/telephony/java/android/telephony/ims/ImsSsInfo.java b/telephony/java/android/telephony/ims/ImsSsInfo.java
index be34f9d..0510a00 100644
--- a/telephony/java/android/telephony/ims/ImsSsInfo.java
+++ b/telephony/java/android/telephony/ims/ImsSsInfo.java
@@ -336,4 +336,31 @@
     public @ClirInterrogationStatus int getClirInterrogationStatus() {
         return mClirInterrogationStatus;
     }
+
+    /**
+     * Parts of telephony still use the old {m,n} 3GPP definition, so convert to that format.
+     * @hide
+     */
+    public int[] getCompatArray(@ImsSsData.ServiceType int type) {
+        int[] result = new int[2];
+        // Convert ImsSsInfo into a form that telephony can read (as per 3GPP 27.007)
+        // CLIR (section 7.7)
+        if (type == ImsSsData.SS_CLIR) {
+            // Assume there will only be one ImsSsInfo.
+            // contains {"n","m"} parameters
+            result[0] = getClirOutgoingState();
+            result[1] = getClirInterrogationStatus();
+            return result;
+        }
+        // COLR 7.31
+        if (type == ImsSsData.SS_COLR) {
+            result[0] = getProvisionStatus();
+        }
+        // Facility Lock CLCK 7.4 (for call barring), CLIP 7.6, COLP 7.8, as well as any
+        // other result, just return the status for the "n" parameter and provisioning status for
+        // "m" as the default.
+        result[0] = getStatus();
+        result[1] = getProvisionStatus();
+        return result;
+    }
 }
diff --git a/telephony/java/android/telephony/ims/ImsUtListener.java b/telephony/java/android/telephony/ims/ImsUtListener.java
index d50a0f7..1a21d0a 100644
--- a/telephony/java/android/telephony/ims/ImsUtListener.java
+++ b/telephony/java/android/telephony/ims/ImsUtListener.java
@@ -16,22 +16,53 @@
 
 package android.telephony.ims;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Bundle;
 import android.os.RemoteException;
+import android.telephony.ims.stub.ImsUtImplBase;
 import android.util.Log;
 
 import com.android.ims.internal.IImsUtListener;
 
 /**
- * Base implementation of the IMS UT listener interface, which implements stubs.
- * Override these methods to implement functionality.
+ * Listener interface used to receive network responses back from UT supplementary service queries
+ * made by the framework.
  * @hide
  */
 // DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
 // will break other implementations of ImsUt maintained by other ImsServices.
 @SystemApi
 public class ImsUtListener {
+
+    /**
+     * The {@link Bundle} key for a Calling Line Identification Restriction (CLIR) response. The
+     * value will be an int[] with two values:
+     * int[0] contains the 'n' parameter from TS 27.007 7.7, which is the
+     * outgoing CLIR state. See {@link ImsSsInfo#CLIR_OUTGOING_DEFAULT},
+     * {@link ImsSsInfo#CLIR_OUTGOING_INVOCATION}, and {@link ImsSsInfo#CLIR_OUTGOING_SUPPRESSION};
+     * int[1] contains the 'm' parameter from TS 27.007 7.7, which is the CLIR interrogation status.
+     * See {@link ImsSsInfo#CLIR_STATUS_NOT_PROVISIONED},
+     * {@link ImsSsInfo#CLIR_STATUS_PROVISIONED_PERMANENT}, {@link ImsSsInfo#CLIR_STATUS_UNKNOWN},
+     * {@link ImsSsInfo#CLIR_STATUS_TEMPORARILY_RESTRICTED}, and
+     * {@link ImsSsInfo#CLIR_STATUS_TEMPORARILY_ALLOWED}.
+     * @deprecated Use {@link #onLineIdentificationSupplementaryServiceResponse(int, ImsSsInfo)}
+     * instead.
+     */
+    @Deprecated
+    public static final String BUNDLE_KEY_CLIR = "queryClir";
+
+    /**
+     * The {@link Bundle} key for a Calling Line Identification Presentation (CLIP), Connected Line
+     * Identification Presentation (COLP), or Connected Line Identification Restriction (COLR)
+     * response. The value will be an instance of {@link ImsSsInfo}, which contains the response to
+     * the query.
+     * @deprecated Use {@link #onLineIdentificationSupplementaryServiceResponse(int, ImsSsInfo)}
+     * instead.
+     */
+    @Deprecated
+    public static final String BUNDLE_KEY_SSINFO = "imsSsInfo";
+
     private IImsUtListener mServiceInterface;
     private static final String LOG_TAG = "ImsUtListener";
 
@@ -51,14 +82,54 @@
         }
     }
 
-    public void onUtConfigurationQueried(int id, Bundle ssInfo) {
+    /**
+     * Notify the framework of a UT configuration response to a {@link ImsUtImplBase#queryClir()},
+     * {@link ImsUtImplBase#queryClip()}, {@link ImsUtImplBase#queryColp()}, or
+     * {@link ImsUtImplBase#queryColr()} query for the transaction ID specified. If the query fails,
+     * {@link #onUtConfigurationQueryFailed(int, ImsReasonInfo)} should be called.
+     * @param id The ID associated with this UT configuration transaction from the framework.
+     * @param configuration A {@link Bundle} containing the result of querying the UT configuration.
+     *                      Must contain {@link #BUNDLE_KEY_CLIR} if it is a response to
+     *                      {@link ImsUtImplBase#queryClir()} or
+     *                      {@link #BUNDLE_KEY_SSINFO} if it is a response to
+     *                      {@link ImsUtImplBase#queryClip()}, {@link ImsUtImplBase#queryColp()}, or
+     *                      {@link ImsUtImplBase#queryColr()}.
+     * @deprecated Use {@link #onLineIdentificationSupplementaryServiceResponse(int, ImsSsInfo)}
+     * instead.
+     */
+    @Deprecated
+    public void onUtConfigurationQueried(int id, Bundle configuration) {
         try {
-            mServiceInterface.utConfigurationQueried(null, id, ssInfo);
+            mServiceInterface.utConfigurationQueried(null, id, configuration);
         } catch (RemoteException e) {
             Log.w(LOG_TAG, "utConfigurationQueried: remote exception");
         }
     }
 
+    /**
+     * Notify the framework of a UT configuration response to a {@link ImsUtImplBase#queryClir()},
+     * {@link ImsUtImplBase#queryClip()}, {@link ImsUtImplBase#queryColp()}, or
+     * {@link ImsUtImplBase#queryColr()} query for the transaction ID specified. If the query fails,
+     * the framework should be notified via
+     * {@link #onUtConfigurationQueryFailed(int, ImsReasonInfo)}.
+     * @param id The ID associated with this UT configuration transaction from the framework.
+     * @param configuration An {@link ImsSsInfo} instance containing the configuration for the
+     *                      line identification supplementary service queried.
+     */
+    public void onLineIdentificationSupplementaryServiceResponse(int id,
+            @NonNull ImsSsInfo configuration) {
+        try {
+            mServiceInterface.lineIdentificationSupplementaryServiceResponse(id, configuration);
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "onLineIdentificationSupplementaryServicesResponse: remote exception");
+        }
+    }
+
+    /**
+     * Notify the Framework of the line identification query failure.
+     * @param id The ID associated with the UT query transaction.
+     * @param error The query failure reason.
+     */
     public void onUtConfigurationQueryFailed(int id, ImsReasonInfo error) {
         try {
             mServiceInterface.utConfigurationQueryFailed(null, id, error);
diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
new file mode 100644
index 0000000..b4c11e3
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -0,0 +1,285 @@
+/*
+ * 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.telephony.ims;
+
+import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.net.Uri;
+import android.os.Binder;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.ims.aidl.IImsRegistrationCallback;
+import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * Manages IMS Service registration state for associated {@link ImsFeature}s.
+ * @hide
+ */
+@SystemApi
+public interface RegistrationManager {
+
+    /**
+     * @hide
+     */
+    // Defines the underlying radio technology type that we have registered for IMS over.
+    @IntDef(prefix = "REGISTRATION_STATE_",
+            value = {
+                    REGISTRATION_STATE_NOT_REGISTERED,
+                    REGISTRATION_STATE_REGISTERING,
+                    REGISTRATION_STATE_REGISTERED
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ImsRegistrationState {}
+
+    /**
+     * The IMS service is currently not registered to the carrier network.
+     */
+    int REGISTRATION_STATE_NOT_REGISTERED = 0;
+
+    /**
+     * The IMS service is currently in the process of registering to the carrier network.
+     */
+    int REGISTRATION_STATE_REGISTERING = 1;
+
+    /**
+     * The IMS service is currently registered to the carrier network.
+     */
+    int REGISTRATION_STATE_REGISTERED = 2;
+
+
+    /**@hide*/
+    // Translate ImsRegistrationImplBase API to new AccessNetworkConstant because WLAN
+    // and WWAN are more accurate constants.
+    Map<Integer, Integer> IMS_REG_TO_ACCESS_TYPE_MAP =
+            new HashMap<Integer, Integer>() {{
+                // Map NONE to -1 to make sure that we handle the REGISTRATION_TECH_NONE
+                // case, since it is defined.
+                put(ImsRegistrationImplBase.REGISTRATION_TECH_NONE, -1);
+                put(ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
+                        AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+                put(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
+                        AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+            }};
+
+    /**
+     * Callback class for receiving IMS network Registration callback events.
+     * @see #registerImsRegistrationCallback(RegistrationCallback, Executor)
+     * @see #unregisterImsRegistrationCallback(RegistrationCallback)
+     */
+    class RegistrationCallback {
+
+        private static class RegistrationBinder extends IImsRegistrationCallback.Stub {
+
+            private final RegistrationCallback mLocalCallback;
+            private Executor mExecutor;
+
+            RegistrationBinder(RegistrationCallback localCallback) {
+                mLocalCallback = localCallback;
+            }
+
+            @Override
+            public void onRegistered(int imsRadioTech) {
+                if (mLocalCallback == null) return;
+
+                Binder.withCleanCallingIdentity(() -> mExecutor.execute(() ->
+                        mLocalCallback.onRegistered(getAccessType(imsRadioTech))));
+            }
+
+            @Override
+            public void onRegistering(int imsRadioTech) {
+                if (mLocalCallback == null) return;
+
+                Binder.withCleanCallingIdentity(() -> mExecutor.execute(() ->
+                        mLocalCallback.onRegistering(getAccessType(imsRadioTech))));
+            }
+
+            @Override
+            public void onDeregistered(ImsReasonInfo info) {
+                if (mLocalCallback == null) return;
+
+                Binder.withCleanCallingIdentity(() ->
+                        mExecutor.execute(() -> mLocalCallback.onUnregistered(info)));
+            }
+
+            @Override
+            public void onTechnologyChangeFailed(int imsRadioTech, ImsReasonInfo info) {
+                if (mLocalCallback == null) return;
+
+                Binder.withCleanCallingIdentity(() ->
+                        mExecutor.execute(() -> mLocalCallback.onTechnologyChangeFailed(
+                                getAccessType(imsRadioTech), info)));
+            }
+
+            @Override
+            public void onSubscriberAssociatedUriChanged(Uri[] uris) {
+                if (mLocalCallback == null) return;
+
+                Binder.withCleanCallingIdentity(() ->
+                        mExecutor.execute(() ->
+                                mLocalCallback.onSubscriberAssociatedUriChanged(uris)));
+            }
+
+            private void setExecutor(Executor executor) {
+                mExecutor = executor;
+            }
+
+            private static int getAccessType(int regType) {
+                if (!RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.containsKey(regType)) {
+                    Log.w("RegistrationManager", "RegistrationBinder - invalid regType returned: "
+                            + regType);
+                    return -1;
+                }
+                return RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.get(regType);
+            }
+        }
+
+        private final RegistrationBinder mBinder = new RegistrationBinder(this);
+
+        /**
+         * Notifies the framework when the IMS Provider is registered to the IMS network.
+         *
+         * @param imsTransportType the radio access technology.
+         */
+        public void onRegistered(@AccessNetworkConstants.TransportType int imsTransportType) {
+        }
+
+        /**
+         * Notifies the framework when the IMS Provider is trying to register the IMS network.
+         *
+         * @param imsTransportType the radio access technology.
+         */
+        public void onRegistering(@AccessNetworkConstants.TransportType int imsTransportType) {
+        }
+
+        /**
+         * Notifies the framework when the IMS Provider is deregistered from the IMS network.
+         *
+         * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
+         */
+        public void onUnregistered(@Nullable ImsReasonInfo info) {
+        }
+
+        /**
+         * A failure has occurred when trying to handover registration to another technology type.
+         *
+         * @param imsTransportType The transport type that has failed to handover registration to.
+         * @param info A {@link ImsReasonInfo} that identifies the reason for failure.
+         */
+        public void onTechnologyChangeFailed(
+                @AccessNetworkConstants.TransportType int imsTransportType,
+                @Nullable ImsReasonInfo info) {
+        }
+
+        /**
+         * Returns a list of subscriber {@link Uri}s associated with this IMS subscription when
+         * it changes. Per RFC3455, an associated URI is a URI that the service provider has
+         * allocated to a user for their own usage. A user's phone number is typically one of the
+         * associated URIs.
+         * @param uris new array of subscriber {@link Uri}s that are associated with this IMS
+         *         subscription.
+         * @hide
+         */
+        public void onSubscriberAssociatedUriChanged(@Nullable Uri[] uris) {
+        }
+
+        /**@hide*/
+        public final IImsRegistrationCallback getBinder() {
+            return mBinder;
+        }
+
+        /**@hide*/
+        //Only exposed as public for compatibility with deprecated ImsManager APIs.
+        public void setExecutor(Executor executor) {
+            mBinder.setExecutor(executor);
+        }
+    }
+
+    /**
+     * Registers a {@link RegistrationCallback} with the system. Use
+     * {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed
+     * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
+     *
+     * When the callback is registered, it will initiate the callback c to be called with the
+     * current registration state.
+     *
+     * @param c The {@link RegistrationCallback} to be added.
+     * @param executor The executor the callback events should be run on.
+     * @see #unregisterImsRegistrationCallback(RegistrationCallback)
+     * @throws ImsException if the subscription associated with this callback is valid, but
+     * the {@link ImsService} associated with the subscription is not available. This can happen if
+     * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
+     * reason.
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    void registerImsRegistrationCallback(@NonNull RegistrationCallback c,
+            @NonNull @CallbackExecutor Executor executor) throws ImsException;
+
+    /**
+     * Removes an existing {@link RegistrationCallback}.
+     *
+     * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+     * etc...), this callback will automatically be removed. If this method is called for an
+     * inactive subscription, it will result in a no-op.
+     *
+     * @param c The {@link RegistrationCallback} to be removed.
+     * @see SubscriptionManager.OnSubscriptionsChangedListener
+     * @see #registerImsRegistrationCallback(RegistrationCallback, Executor)
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c);
+
+    /**
+     * Gets the registration state of the IMS service.
+     * @param stateCallback A callback called on the supplied {@link Executor} that will contain the
+     *                      registration state of the IMS service, which will be one of the
+     *                      following: {@link #REGISTRATION_STATE_NOT_REGISTERED},
+     *                      {@link #REGISTRATION_STATE_REGISTERING}, or
+     *                      {@link #REGISTRATION_STATE_REGISTERED}.
+     * @param executor The {@link Executor} that will be used to call the IMS registration state
+     *                 callback.
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    void getRegistrationState(@NonNull @ImsRegistrationState Consumer<Integer> stateCallback,
+            @NonNull @CallbackExecutor Executor executor);
+
+    /**
+     * Gets the Transport Type associated with the current IMS registration.
+     * @param transportTypeCallback The transport type associated with the current IMS registration,
+     *                              which will be one of following:
+     *                              {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN},
+     *                              {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, or
+     *                              {@link AccessNetworkConstants#TRANSPORT_TYPE_INVALID}.
+     * @param executor The {@link Executor} that will be used to call the transportTypeCallback.
+     */
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    void getRegistrationTransportType(
+            @NonNull @AccessNetworkConstants.TransportType Consumer<Integer> transportTypeCallback,
+            @NonNull @CallbackExecutor Executor executor);
+}
diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsUtListenerImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsUtListenerImplBase.java
index 976c2be..ae113f2 100644
--- a/telephony/java/android/telephony/ims/compat/stub/ImsUtListenerImplBase.java
+++ b/telephony/java/android/telephony/ims/compat/stub/ImsUtListenerImplBase.java
@@ -18,12 +18,11 @@
 
 import android.os.Bundle;
 import android.os.RemoteException;
-
-import android.annotation.UnsupportedAppUsage;
 import android.telephony.ims.ImsCallForwardInfo;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.ImsSsData;
 import android.telephony.ims.ImsSsInfo;
+
 import com.android.ims.internal.IImsUt;
 import com.android.ims.internal.IImsUtListener;
 
@@ -65,6 +64,13 @@
     }
 
     /**
+     * Notifies the result of a line identification supplementary service query.
+     */
+    @Override
+    public void lineIdentificationSupplementaryServiceResponse(int id, ImsSsInfo config) {
+    }
+
+    /**
      * Notifies the status of the call barring supplementary service.
      */
     @Override
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index ceb4704..8b27b6f 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -362,6 +362,25 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface ProcessCallResult {}
 
+    /**
+     * If the flag is present and true, it indicates that the incoming call is for USSD.
+     * <p>
+     * This is an optional boolean flag.
+     */
+    public static final String EXTRA_IS_USSD = "android.telephony.ims.feature.extra.IS_USSD";
+
+    /**
+     * If this flag is present and true, this call is marked as an unknown dialing call instead
+     * of an incoming call. An example of such a call is a call that is originated by sending
+     * commands (like AT commands) directly to the modem without Android involvement or dialing
+     * calls appearing over IMS when the modem does a silent redial from circuit-switched to IMS in
+     * certain situations.
+     * <p>
+     * This is an optional boolean flag.
+     */
+    public static final String EXTRA_IS_UNKNOWN_CALL =
+            "android.telephony.ims.feature.extra.IS_UNKNOWN_CALL";
+
     private IImsMmTelListener mListener;
 
     /**
@@ -410,6 +429,8 @@
     /**
      * Notify the framework of an incoming call.
      * @param c The {@link ImsCallSessionImplBase} of the new incoming call.
+     * @param extras A bundle containing extra parameters related to the call. See
+     * {@link #EXTRA_IS_UNKNOWN_CALL} and {@link #EXTRA_IS_USSD} above.
      */
     public final void notifyIncomingCall(@NonNull ImsCallSessionImplBase c,
             @NonNull Bundle extras) {
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index a08e031..b455c2e 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -22,6 +22,7 @@
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.RegistrationManager;
 import android.telephony.ims.aidl.IImsRegistration;
 import android.telephony.ims.aidl.IImsRegistrationCallback;
 import android.util.Log;
@@ -72,9 +73,6 @@
     // with NOT_REGISTERED in the case where the ImsService has not updated the registration state
     // yet.
     private static final int REGISTRATION_STATE_UNKNOWN = -1;
-    private static final int REGISTRATION_STATE_NOT_REGISTERED = 0;
-    private static final int REGISTRATION_STATE_REGISTERING = 1;
-    private static final int REGISTRATION_STATE_REGISTERED = 2;
 
     private final IImsRegistration mBinder = new IImsRegistration.Stub() {
 
@@ -128,7 +126,7 @@
      * {@link #REGISTRATION_TECH_LTE} and {@link #REGISTRATION_TECH_IWLAN}.
      */
     public final void onRegistered(@ImsRegistrationTech int imsRadioTech) {
-        updateToState(imsRadioTech, REGISTRATION_STATE_REGISTERED);
+        updateToState(imsRadioTech, RegistrationManager.REGISTRATION_STATE_REGISTERED);
         mCallbacks.broadcast((c) -> {
             try {
                 c.onRegistered(imsRadioTech);
@@ -146,7 +144,7 @@
      * {@link #REGISTRATION_TECH_LTE} and {@link #REGISTRATION_TECH_IWLAN}.
      */
     public final void onRegistering(@ImsRegistrationTech int imsRadioTech) {
-        updateToState(imsRadioTech, REGISTRATION_STATE_REGISTERING);
+        updateToState(imsRadioTech, RegistrationManager.REGISTRATION_STATE_REGISTERING);
         mCallbacks.broadcast((c) -> {
             try {
                 c.onRegistering(imsRadioTech);
@@ -230,7 +228,8 @@
 
     private void updateToDisconnectedState(ImsReasonInfo info) {
         synchronized (mLock) {
-            updateToState(REGISTRATION_TECH_NONE, REGISTRATION_STATE_NOT_REGISTERED);
+            updateToState(REGISTRATION_TECH_NONE,
+                    RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED);
             if (info != null) {
                 mLastDisconnectCause = info;
             } else {
@@ -264,15 +263,15 @@
             disconnectInfo = mLastDisconnectCause;
         }
         switch (state) {
-            case REGISTRATION_STATE_NOT_REGISTERED: {
+            case RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED: {
                 c.onDeregistered(disconnectInfo);
                 break;
             }
-            case REGISTRATION_STATE_REGISTERING: {
+            case RegistrationManager.REGISTRATION_STATE_REGISTERING: {
                 c.onRegistering(getConnectionType());
                 break;
             }
-            case REGISTRATION_STATE_REGISTERED: {
+            case RegistrationManager.REGISTRATION_STATE_REGISTERED: {
                 c.onRegistered(getConnectionType());
                 break;
             }
diff --git a/telephony/java/com/android/ims/internal/IImsUtListener.aidl b/telephony/java/com/android/ims/internal/IImsUtListener.aidl
index fcb9fb1..9a12cee 100644
--- a/telephony/java/com/android/ims/internal/IImsUtListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsUtListener.aidl
@@ -44,6 +44,7 @@
     @UnsupportedAppUsage
     void utConfigurationQueryFailed(in IImsUt ut, int id, in ImsReasonInfo error);
 
+    void lineIdentificationSupplementaryServiceResponse(int id, in ImsSsInfo config);
     /**
      * Notifies the status of the call barring supplementary service.
      */
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index f3a335d..91aa3ce 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -574,4 +574,23 @@
      * @param destAddress the destination address to test for possible short code
      */
     int checkSmsShortCodeDestination(int subId, String callingApk, String destAddress, String countryIso);
+
+    /**
+     * Gets the SMSC address from (U)SIM.
+     *
+     * @param subId the subscription Id.
+     * @param callingPackage the package name of the calling app.
+     * @return the SMSC address string, null if failed.
+     */
+    String getSmscAddressFromIccEfForSubscriber(int subId, String callingPackage);
+
+    /**
+     * Sets the SMSC address on (U)SIM.
+     *
+     * @param smsc the SMSC address string.
+     * @param subId the subscription Id.
+     * @param callingPackage the package name of the calling app.
+     * @return true for success, false otherwise.
+     */
+    boolean setSmscAddressOnIccEfForSubscriber(String smsc, int subId, String callingPackage);
 }
diff --git a/telephony/java/com/android/internal/telephony/ISmsImplBase.java b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
index 2096325..d9d4b60 100644
--- a/telephony/java/com/android/internal/telephony/ISmsImplBase.java
+++ b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
@@ -201,4 +201,15 @@
             int subid, String callingApk, String destAddress, String countryIso) {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public String getSmscAddressFromIccEfForSubscriber(int subId, String callingPackage) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean setSmscAddressOnIccEfForSubscriber(
+            String smsc, int subId, String callingPackage) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 39e00cc..c6c9f34 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -295,7 +295,7 @@
      */
     boolean isDataConnectivityPossible(int subId);
 
-    Bundle getCellLocation(String callingPkg);
+    Bundle getCellLocation(String callingPkg, String callingFeatureId);
 
     /**
      * Returns the ISO country code equivalent of the current registered
@@ -307,7 +307,7 @@
     /**
      * Returns the neighboring cell information of the device.
      */
-    List<NeighboringCellInfo> getNeighboringCellInfo(String callingPkg);
+    List<NeighboringCellInfo> getNeighboringCellInfo(String callingPkg, String callingFeatureId);
 
     @UnsupportedAppUsage
     int getCallState();
@@ -556,13 +556,14 @@
     /**
      * Returns all observed cell information of the device.
      */
-    List<CellInfo> getAllCellInfo(String callingPkg);
+    List<CellInfo> getAllCellInfo(String callingPkg, String callingFeatureId);
 
     /**
      * Request a cell information update for the specified subscription,
      * reported via the CellInfoCallback.
      */
-    void requestCellInfoUpdate(int subId, in ICellInfoCallback cb, String callingPkg);
+    void requestCellInfoUpdate(int subId, in ICellInfoCallback cb, String callingPkg,
+            String callingFeatureId);
 
     /**
      * Request a cell information update for the specified subscription,
@@ -570,8 +571,8 @@
      *
      * @param workSource the requestor to whom the power consumption for this should be attributed.
      */
-    void requestCellInfoUpdateWithWorkSource(
-            int subId, in ICellInfoCallback cb, in String callingPkg, in WorkSource ws);
+    void requestCellInfoUpdateWithWorkSource(int subId, in ICellInfoCallback cb,
+            in String callingPkg, String callingFeatureId, in WorkSource ws);
 
     /**
      * Sets minimum time in milli-seconds between onCellInfoChanged
@@ -867,6 +868,11 @@
     String getImsService(int slotId, boolean isCarrierImsService);
 
     /**
+     * Get the MmTelFeature state attached to this subscription id.
+     */
+    void getImsMmTelFeatureState(int subId, IIntegerConsumer callback);
+
+    /**
      * Set the network selection mode to automatic.
      *
      * @param subId the id of the subscription to update.
@@ -877,9 +883,12 @@
      * Perform a radio scan and return the list of avialble networks.
      *
      * @param subId the id of the subscription.
+     * @param callingPackage the calling package
+     * @param callingFeatureId The feature in the package
      * @return CellNetworkScanResult containing status of scan and networks.
      */
-    CellNetworkScanResult getCellNetworkScanResults(int subId, String callingPackage);
+    CellNetworkScanResult getCellNetworkScanResults(int subId, String callingPackage,
+            String callingFeatureId);
 
     /**
      * Perform a radio network scan and return the id of this scan.
@@ -889,10 +898,11 @@
      * @param messenger Callback messages will be sent using this messenger.
      * @param binder the binder object instantiated in TelephonyManager.
      * @param callingPackage the calling package
+     * @param callingFeatureId The feature in the package
      * @return An id for this scan.
      */
     int requestNetworkScan(int subId, in NetworkScanRequest request, in Messenger messenger,
-            in IBinder binder, in String callingPackage);
+            in IBinder binder, in String callingPackage, String callingFeatureId);
 
     /**
      * Stop an existing radio network scan.
@@ -1308,6 +1318,12 @@
     int getSubIdForPhoneAccount(in PhoneAccount phoneAccount);
 
     /**
+     * Returns the subscription ID associated with the specified PhoneAccountHandle.
+     */
+    int getSubIdForPhoneAccountHandle(in PhoneAccountHandle phoneAccountHandle,
+            String callingPackage);
+
+    /**
      * Returns the PhoneAccountHandle associated with a subscription ID.
      */
     PhoneAccountHandle getPhoneAccountHandleForSubscriptionId(int subscriptionId);
@@ -1335,9 +1351,11 @@
      * Get the service state on specified subscription
      * @param subId Subscription id
      * @param callingPackage The package making the call
+     * @param callingFeatureId The feature in the package
      * @return Service state on specified subscription.
      */
-    ServiceState getServiceStateForSubscriber(int subId, String callingPackage);
+    ServiceState getServiceStateForSubscriber(int subId, String callingPackage,
+            String callingFeatureId);
 
     /**
      * Returns the URI for the per-account voicemail ringtone set in Phone settings.
@@ -1778,21 +1796,6 @@
      boolean isInEmergencySmsMode();
 
     /**
-     * Get a list of SMS apps on a user.
-     */
-    String[] getSmsApps(int userId);
-
-    /**
-     * Get the default SMS app on a given user.
-     */
-    String getDefaultSmsApp(int userId);
-
-    /**
-     * Set the default SMS app to a given package on a given user.
-     */
-    void setDefaultSmsApp(int userId, String packageName);
-
-    /**
      * Return the modem radio power state for slot index.
      *
      */
@@ -1810,6 +1813,16 @@
     void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback c);
 
     /**
+     * Get the IMS service registration state for the MmTelFeature associated with this sub id.
+     */
+    void getImsMmTelRegistrationState(int subId, IIntegerConsumer consumer);
+
+    /**
+     * Get the transport type for the IMS service registration state.
+     */
+    void getImsMmTelRegistrationTransportType(int subId, IIntegerConsumer consumer);
+
+    /**
      * Adds an IMS MmTel capabilities callback for the subscription specified.
      */
     void registerMmTelCapabilityCallback(int subId, IImsCapabilityCallback c);
@@ -1830,6 +1843,12 @@
     boolean isAvailable(int subId, int capability, int regTech);
 
     /**
+     * Return whether or not the MmTel capability is supported for the requested transport type.
+     */
+    void isMmTelCapabilitySupported(int subId, IIntegerConsumer callback, int capability,
+            int transportType);
+
+    /**
      * Returns true if the user's setting for 4G LTE is enabled, for the subscription specified.
      */
     boolean isAdvancedCallingSettingEnabled(int subId);
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index 81b1e49..0b5d446 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -19,8 +19,14 @@
 java_sdk_library {
     name: "android.test.mock",
 
-    srcs: ["src/**/*.java"],
-    api_srcs: [":framework-all-sources"],
+    srcs: [
+        "src/**/*.java",
+        // Note: Below are NOT APIs of this library. We only take APIs under
+        // the android.test.mock package. They however provide private APIs that
+        // android.test.mock APIs references to.
+        ":framework-core-sources-for-test-mock",
+        ":framework_native_aidl",
+    ],
     libs: ["framework-all"],
 
     api_packages: [
diff --git a/test-mock/src/android/test/mock/MockContentProvider.java b/test-mock/src/android/test/mock/MockContentProvider.java
index 4d8c7d9..9d3e120 100644
--- a/test-mock/src/android/test/mock/MockContentProvider.java
+++ b/test-mock/src/android/test/mock/MockContentProvider.java
@@ -56,21 +56,22 @@
      */
     private class InversionIContentProvider implements IContentProvider {
         @Override
-        public ContentProviderResult[] applyBatch(String callingPackage, String authority,
+        public ContentProviderResult[] applyBatch(String callingPackage,
+                @Nullable String featureId, String authority,
                 ArrayList<ContentProviderOperation> operations)
                 throws RemoteException, OperationApplicationException {
             return MockContentProvider.this.applyBatch(authority, operations);
         }
 
         @Override
-        public int bulkInsert(String callingPackage, Uri url, ContentValues[] initialValues)
-                throws RemoteException {
+        public int bulkInsert(String callingPackage, @Nullable String featureId, Uri url,
+                ContentValues[] initialValues) throws RemoteException {
             return MockContentProvider.this.bulkInsert(url, initialValues);
         }
 
         @Override
-        public int delete(String callingPackage, Uri url, String selection, String[] selectionArgs)
-                throws RemoteException {
+        public int delete(String callingPackage, @Nullable String featureId, Uri url,
+                String selection, String[] selectionArgs) throws RemoteException {
             return MockContentProvider.this.delete(url, selection, selectionArgs);
         }
 
@@ -80,42 +81,42 @@
         }
 
         @Override
-        public Uri insert(String callingPackage, Uri url, ContentValues initialValues)
-                throws RemoteException {
+        public Uri insert(String callingPackage, @Nullable String featureId, Uri url,
+                ContentValues initialValues) throws RemoteException {
             return MockContentProvider.this.insert(url, initialValues);
         }
 
         @Override
-        public AssetFileDescriptor openAssetFile(
-                String callingPackage, Uri url, String mode, ICancellationSignal signal)
+        public AssetFileDescriptor openAssetFile(String callingPackage,
+                @Nullable String featureId, Uri url, String mode, ICancellationSignal signal)
                 throws RemoteException, FileNotFoundException {
             return MockContentProvider.this.openAssetFile(url, mode);
         }
 
         @Override
-        public ParcelFileDescriptor openFile(
-                String callingPackage, Uri url, String mode, ICancellationSignal signal,
-                IBinder callerToken) throws RemoteException, FileNotFoundException {
+        public ParcelFileDescriptor openFile(String callingPackage, @Nullable String featureId,
+                Uri url, String mode, ICancellationSignal signal, IBinder callerToken)
+                throws RemoteException, FileNotFoundException {
             return MockContentProvider.this.openFile(url, mode);
         }
 
         @Override
-        public Cursor query(String callingPackage, Uri url, @Nullable String[] projection,
-                @Nullable Bundle queryArgs,
-                @Nullable ICancellationSignal cancellationSignal)
-                throws RemoteException {
+        public Cursor query(String callingPackage, @Nullable String featureId, Uri url,
+                @Nullable String[] projection, @Nullable Bundle queryArgs,
+                @Nullable ICancellationSignal cancellationSignal) throws RemoteException {
             return MockContentProvider.this.query(url, projection, queryArgs, null);
         }
 
         @Override
-        public int update(String callingPackage, Uri url, ContentValues values, String selection,
-                String[] selectionArgs) throws RemoteException {
+        public int update(String callingPackage, @Nullable String featureId, Uri url,
+                ContentValues values, String selection, String[] selectionArgs)
+                throws RemoteException {
             return MockContentProvider.this.update(url, values, selection, selectionArgs);
         }
 
         @Override
-        public Bundle call(String callingPackage, String authority, String method, String request,
-                Bundle args) throws RemoteException {
+        public Bundle call(String callingPackage, @Nullable String featureId, String authority,
+                String method, String request, Bundle args) throws RemoteException {
             return MockContentProvider.this.call(authority, method, request, args);
         }
 
@@ -130,9 +131,9 @@
         }
 
         @Override
-        public AssetFileDescriptor openTypedAssetFile(String callingPackage, Uri url,
-                String mimeType, Bundle opts, ICancellationSignal signal)
-                throws RemoteException, FileNotFoundException {
+        public AssetFileDescriptor openTypedAssetFile(String callingPackage,
+                @Nullable String featureId, Uri url, String mimeType, Bundle opts,
+                ICancellationSignal signal) throws RemoteException, FileNotFoundException {
             return MockContentProvider.this.openTypedAssetFile(url, mimeType, opts);
         }
 
@@ -142,23 +143,26 @@
         }
 
         @Override
-        public Uri canonicalize(String callingPkg, Uri uri) throws RemoteException {
+        public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri)
+                throws RemoteException {
             return MockContentProvider.this.canonicalize(uri);
         }
 
         @Override
-        public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException {
+        public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri)
+                throws RemoteException {
             return MockContentProvider.this.uncanonicalize(uri);
         }
 
         @Override
-        public boolean refresh(String callingPkg, Uri url, Bundle args,
-                ICancellationSignal cancellationSignal) throws RemoteException {
+        public boolean refresh(String callingPkg, @Nullable String featureId, Uri url,
+                Bundle args, ICancellationSignal cancellationSignal) throws RemoteException {
             return MockContentProvider.this.refresh(url, args);
         }
 
         @Override
-        public int checkUriPermission(String callingPkg, Uri uri, int uid, int modeFlags) {
+        public int checkUriPermission(String callingPkg, @Nullable String featureId, Uri uri,
+                int uid, int modeFlags) {
             return MockContentProvider.this.checkUriPermission(uri, uid, modeFlags);
         }
     }
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 5053cee..1de6260 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -463,6 +463,13 @@
     }
 
     @Override
+    public void sendOrderedBroadcast(Intent intent, String receiverPermission,
+            String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public void sendStickyBroadcast(Intent intent) {
         throw new UnsupportedOperationException();
     }
diff --git a/test-mock/src/android/test/mock/MockIContentProvider.java b/test-mock/src/android/test/mock/MockIContentProvider.java
index b072d74..e512b52 100644
--- a/test-mock/src/android/test/mock/MockIContentProvider.java
+++ b/test-mock/src/android/test/mock/MockIContentProvider.java
@@ -16,14 +16,12 @@
 
 package android.test.mock;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ContentProviderOperation;
 import android.content.ContentProviderResult;
 import android.content.ContentValues;
 import android.content.EntityIterator;
 import android.content.IContentProvider;
-import android.content.Intent;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.net.Uri;
@@ -45,14 +43,15 @@
  */
 public class MockIContentProvider implements IContentProvider {
     @Override
-    public int bulkInsert(String callingPackage, Uri url, ContentValues[] initialValues) {
+    public int bulkInsert(String callingPackage, @Nullable String featureId, Uri url,
+            ContentValues[] initialValues) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
     @Override
     @SuppressWarnings("unused")
-    public int delete(String callingPackage, Uri url, String selection, String[] selectionArgs)
-            throws RemoteException {
+    public int delete(String callingPackage, @Nullable String featureId, Uri url,
+            String selection, String[] selectionArgs) throws RemoteException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
@@ -63,33 +62,33 @@
 
     @Override
     @SuppressWarnings("unused")
-    public Uri insert(String callingPackage, Uri url, ContentValues initialValues)
-            throws RemoteException {
+    public Uri insert(String callingPackage, @Nullable String featureId, Uri url,
+            ContentValues initialValues) throws RemoteException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
     @Override
-    public ParcelFileDescriptor openFile(
-            String callingPackage, Uri url, String mode, ICancellationSignal signal,
-            IBinder callerToken) {
+    public ParcelFileDescriptor openFile(String callingPackage, @Nullable String featureId,
+            Uri url, String mode, ICancellationSignal signal, IBinder callerToken) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
     @Override
-    public AssetFileDescriptor openAssetFile(
-            String callingPackage, Uri uri, String mode, ICancellationSignal signal) {
+    public AssetFileDescriptor openAssetFile(String callingPackage, @Nullable String featureId,
+            Uri uri, String mode, ICancellationSignal signal) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
     @Override
-    public ContentProviderResult[] applyBatch(String callingPackage, String authority,
-            ArrayList<ContentProviderOperation> operations) {
+    public ContentProviderResult[] applyBatch(String callingPackage, @Nullable String featureId,
+            String authority, ArrayList<ContentProviderOperation> operations) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
     @Override
-    public Cursor query(String callingPackage, Uri url, @Nullable String[] projection,
-            @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal) {
+    public Cursor query(String callingPackage, @Nullable String featureId, Uri url,
+            @Nullable String[] projection, @Nullable Bundle queryArgs,
+            @Nullable ICancellationSignal cancellationSignal) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
@@ -99,14 +98,14 @@
     }
 
     @Override
-    public int update(String callingPackage, Uri url, ContentValues values, String selection,
-            String[] selectionArgs) throws RemoteException {
+    public int update(String callingPackage, @Nullable String featureId, Uri url,
+            ContentValues values, String selection, String[] selectionArgs) throws RemoteException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
     @Override
-    public Bundle call(String callingPackage, String authority, String method, String request,
-            Bundle args) throws RemoteException {
+    public Bundle call(String callingPackage, @Nullable String featureId, String authority,
+            String method, String request, Bundle args) throws RemoteException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
@@ -121,8 +120,9 @@
     }
 
     @Override
-    public AssetFileDescriptor openTypedAssetFile(String callingPackage, Uri url, String mimeType,
-            Bundle opts, ICancellationSignal signal) throws RemoteException, FileNotFoundException {
+    public AssetFileDescriptor openTypedAssetFile(String callingPackage,
+            @Nullable String featureId, Uri url, String mimeType, Bundle opts,
+            ICancellationSignal signal) throws RemoteException, FileNotFoundException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
@@ -132,24 +132,27 @@
     }
 
     @Override
-    public Uri canonicalize(String callingPkg, Uri uri) throws RemoteException {
+    public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri)
+            throws RemoteException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
     @Override
-    public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException {
+    public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri)
+            throws RemoteException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
     @Override
-    public boolean refresh(String callingPkg, Uri url, Bundle args,
+    public boolean refresh(String callingPkg, @Nullable String featureId, Uri url, Bundle args,
             ICancellationSignal cancellationSignal) throws RemoteException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
     /** {@hide} */
     @Override
-    public int checkUriPermission(String callingPkg, Uri uri, int uid, int modeFlags) {
+    public int checkUriPermission(String callingPkg, @Nullable String featureId, Uri uri, int uid,
+            int modeFlags) {
         throw new UnsupportedOperationException("unimplemented mock method call");
     }
 }
diff --git a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
index ccdd452..74aaec1 100644
--- a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
+++ b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
@@ -54,11 +54,15 @@
         assertTrue("profile system server not enabled", res != null && res.equals("true"));
     }
 
-    private void forceSaveProfile(String pkg) throws Exception {
+    private boolean forceSaveProfile(String pkg) throws Exception {
         String pid = mTestDevice.executeShellCommand("pidof " + pkg).trim();
-        assertTrue("Invalid pid " + pid, pid.length() > 0);
+        if (pid.length() == 0) {
+            // Not yet running.
+            return false;
+        }
         String res = mTestDevice.executeShellCommand("kill -s SIGUSR1 " + pid).trim();
         assertTrue("kill SIGUSR1: " + res, res.length() == 0);
+        return true;
     }
 
     @Test
@@ -71,10 +75,13 @@
         // Wait up to 20 seconds for the profile to be saved.
         for (int i = 0; i < 20; ++i) {
             // Force save the profile since we truncated it.
-            forceSaveProfile("system_server");
-            String s = mTestDevice.executeShellCommand("wc -c <" + SYSTEM_SERVER_PROFILE).trim();
-            if (!"0".equals(s)) {
-                break;
+            if (forceSaveProfile("system_server")) {
+                // Might fail if system server is not yet running.
+                String s = mTestDevice.executeShellCommand(
+                        "wc -c <" + SYSTEM_SERVER_PROFILE).trim();
+                if (!"0".equals(s)) {
+                    break;
+                }
             }
             Thread.sleep(1000);
         }
@@ -87,6 +94,8 @@
         boolean sawServices = false;
         for (String line : res.split("\n")) {
             if (line.contains("framework.jar")) {
+                sawFramework = true;  // Legacy
+            } else if (line.contains("framework-minus-apex.jar")) {
                 sawFramework = true;
             } else if (line.contains("services.jar")) {
                 sawServices = true;
@@ -99,13 +108,18 @@
         // Test the profile contents contain common methods for core-oj that would normally be AOT
         // compiled.
         res = mTestDevice.executeShellCommand("profman --dump-classes-and-methods --profile-file="
-                + SYSTEM_SERVER_PROFILE + " --apk=/apex/com.android.art/javalib/core-oj.jar");
+                + SYSTEM_SERVER_PROFILE + " --apk=/apex/com.android.art/javalib/core-oj.jar"
+                + " --apk=/system/framework/services.jar");
         boolean sawObjectInit = false;
+        boolean sawPmInit = false;
         for (String line : res.split("\n")) {
             if (line.contains("Ljava/lang/Object;-><init>()V")) {
                 sawObjectInit = true;
+            } else if (line.contains("Lcom/android/server/pm/PackageManagerService;-><init>")) {
+                sawPmInit = true;
             }
         }
         assertTrue("Did not see Object.<init> in " + res, sawObjectInit);
+        assertTrue("Did not see PackageManagerService.<init> in " + res, sawPmInit);
     }
 }
diff --git a/tests/Codegen/runTest.sh b/tests/Codegen/runTest.sh
index 929f122..31ab6d2 100755
--- a/tests/Codegen/runTest.sh
+++ b/tests/Codegen/runTest.sh
@@ -17,6 +17,7 @@
         header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java && \
         header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java && \
         header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java && \
+        header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java && \
         (
             cd $ANDROID_BUILD_TOP &&
             header_and_eval mmma -j16 frameworks/base/tests/Codegen && \
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
index 325c1c0..7d88161 100644
--- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
@@ -32,7 +32,7 @@
 
 
 
-    // Code below generated by codegen v1.0.9.
+    // Code below generated by codegen v1.0.12.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -98,11 +98,15 @@
     };
 
     @DataClass.Generated(
-            time = 1571258914826L,
-            codegenVersion = "1.0.9",
+            time = 1572655992854L,
+            codegenVersion = "1.0.12",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java",
             inputSignatures = "private  int mBaseData\nclass HierrarchicalDataClassBase extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genSetters=true)")
     @Deprecated
     private void __metadata() {}
 
+
+    //@formatter:on
+    // End of generated code
+
 }
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
index 6c92009..c930ce5 100644
--- a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
@@ -46,7 +46,7 @@
 
 
 
-    // Code below generated by codegen v1.0.9.
+    // Code below generated by codegen v1.0.12.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -120,11 +120,15 @@
     };
 
     @DataClass.Generated(
-            time = 1571258915848L,
-            codegenVersion = "1.0.9",
+            time = 1572655993858L,
+            codegenVersion = "1.0.12",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java",
             inputSignatures = "private @android.annotation.NonNull java.lang.String mChildData\nclass HierrarchicalDataClassChild extends com.android.codegentest.HierrarchicalDataClassBase implements []\n@com.android.internal.util.DataClass(genParcelable=true, genConstructor=false, genSetters=true)")
     @Deprecated
     private void __metadata() {}
 
+
+    //@formatter:on
+    // End of generated code
+
 }
diff --git a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
index 36def8a..368a5c3 100644
--- a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
@@ -52,7 +52,7 @@
 
 
 
-    // Code below generated by codegen v1.0.9.
+    // Code below generated by codegen v1.0.12.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -361,7 +361,7 @@
         }
 
         /** Builds the instance. This builder should not be touched after calling this! */
-        public ParcelAllTheThingsDataClass build() {
+        public @NonNull ParcelAllTheThingsDataClass build() {
             checkNotUsed();
             mBuilderFieldsSet |= 0x100; // Mark builder used
 
@@ -410,11 +410,15 @@
     }
 
     @DataClass.Generated(
-            time = 1571258913802L,
-            codegenVersion = "1.0.9",
+            time = 1572655991821L,
+            codegenVersion = "1.0.12",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java",
             inputSignatures = " @android.annotation.NonNull java.lang.String[] mStringArray\n @android.annotation.NonNull int[] mIntArray\n @android.annotation.NonNull java.util.List<java.lang.String> mStringList\n @android.annotation.NonNull java.util.Map<java.lang.String,com.android.codegentest.SampleWithCustomBuilder> mMap\n @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.String> mStringMap\n @android.annotation.NonNull android.util.SparseArray<com.android.codegentest.SampleWithCustomBuilder> mSparseArray\n @android.annotation.NonNull android.util.SparseIntArray mSparseIntArray\n @java.lang.SuppressWarnings({\"WeakerAccess\"}) @android.annotation.Nullable java.lang.Boolean mNullableBoolean\nclass ParcelAllTheThingsDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)")
     @Deprecated
     private void __metadata() {}
 
+
+    //@formatter:on
+    // End of generated code
+
 }
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
index c444d61..9d52287 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
@@ -342,7 +342,7 @@
 
 
 
-    // Code below generated by codegen v1.0.9.
+    // Code below generated by codegen v1.0.12.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -1430,7 +1430,7 @@
      */
     @SuppressWarnings("WeakerAccess")
     @DataClass.Generated.Member
-    public static class Builder {
+    public static final class Builder {
 
         private int mNum;
         private int mNum2;
@@ -1793,7 +1793,7 @@
         }
 
         /** Builds the instance. This builder should not be touched after calling this! */
-        public SampleDataClass build() {
+        public @NonNull SampleDataClass build() {
             checkNotUsed();
             mBuilderFieldsSet |= 0x100000; // Mark builder used
 
@@ -1872,11 +1872,15 @@
     }
 
     @DataClass.Generated(
-            time = 1571258911688L,
-            codegenVersion = "1.0.9",
+            time = 1572655989589L,
+            codegenVersion = "1.0.12",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java",
             inputSignatures = "public static final  java.lang.String STATE_NAME_UNDEFINED\npublic static final  java.lang.String STATE_NAME_ON\npublic static final  java.lang.String STATE_NAME_OFF\npublic static final  int STATE_UNDEFINED\npublic static final  int STATE_ON\npublic static final  int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate  int mNum\nprivate  int mNum2\nprivate  int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient  android.net.LinkAddress[] mLinkAddresses6\ntransient  int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=6L) int mDayOfWeek\nprivate @android.annotation.Size(2L) @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate static  java.lang.String defaultName4()\nprivate  int[] lazyInitTmpStorage()\npublic  android.net.LinkAddress[] getLinkAddresses4()\nprivate  boolean patternEquals(java.util.regex.Pattern)\nprivate  int patternHashCode()\nprivate  void onConstructed()\npublic  void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)")
     @Deprecated
     private void __metadata() {}
 
+
+    //@formatter:on
+    // End of generated code
+
 }
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java b/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java
index c7a7735..d132577 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClassTest.java
@@ -243,6 +243,26 @@
         assertEquals(instance.toString(), unparceledInstance.toString());
     }
 
+    @Test
+    public void testNestedDataClasses_notMangledWhenParceled() {
+        assertEqualsAfterParcelling(
+                new SampleWithNestedDataClasses.NestedDataClass("1"),
+                SampleWithNestedDataClasses.NestedDataClass.CREATOR);
+
+        assertEqualsAfterParcelling(
+                new SampleWithNestedDataClasses.NestedDataClass2("2"),
+                SampleWithNestedDataClasses.NestedDataClass2.CREATOR);
+
+        assertEqualsAfterParcelling(
+                new SampleWithNestedDataClasses.NestedDataClass2.NestedDataClass3(3),
+                SampleWithNestedDataClasses.NestedDataClass2.NestedDataClass3.CREATOR);
+    }
+
+    private static <T extends Parcelable> void assertEqualsAfterParcelling(
+            T p, Parcelable.Creator<T> creator) {
+        assertEquals(p, parcelAndUnparcel(p, creator));
+    }
+
     private static <T extends Parcelable> T parcelAndUnparcel(
             T original, Parcelable.Creator<T> creator) {
         Parcel p = Parcel.obtain();
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
index 55feae7..cef32d1 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
@@ -85,7 +85,7 @@
 
 
 
-    // Code below generated by codegen v1.0.9.
+    // Code below generated by codegen v1.0.12.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -224,7 +224,7 @@
         }
 
         /** Builds the instance. This builder should not be touched after calling this! */
-        public SampleWithCustomBuilder build() {
+        public @NonNull SampleWithCustomBuilder build() {
             checkNotUsed();
             mBuilderFieldsSet |= 0x8; // Mark builder used
 
@@ -253,11 +253,15 @@
     }
 
     @DataClass.Generated(
-            time = 1571258912752L,
-            codegenVersion = "1.0.9",
+            time = 1572655990725L,
+            codegenVersion = "1.0.12",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java",
             inputSignatures = "  long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n  long creationTimestamp\nprivate static  java.util.concurrent.TimeUnit unparcelDelayUnit(android.os.Parcel)\nprivate  void parcelDelayUnit(android.os.Parcel,int)\nclass SampleWithCustomBuilder extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)\nabstract  com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract  com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic  com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []")
     @Deprecated
     private void __metadata() {}
 
+
+    //@formatter:on
+    // End of generated code
+
 }
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java b/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
new file mode 100644
index 0000000..27055f6
--- /dev/null
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
@@ -0,0 +1,390 @@
+/*
+ * 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.codegentest;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * An example of deeply nested data classes
+ */
+public class SampleWithNestedDataClasses {
+
+    int mFoo = 0;
+
+    @DataClass(genEqualsHashCode = true)
+    public static class NestedDataClass implements Parcelable {
+
+        @NonNull String mBar;
+
+
+
+        // Code below generated by codegen v1.0.12.
+        //
+        // DO NOT MODIFY!
+        // CHECKSTYLE:OFF Generated code
+        //
+        // To regenerate run:
+        // $ codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
+        //
+        // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+        //   Settings > Editor > Code Style > Formatter Control
+        //@formatter:off
+
+
+        @DataClass.Generated.Member
+        public NestedDataClass(
+                @NonNull String bar) {
+            this.mBar = bar;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, mBar);
+
+            // onConstructed(); // You can define this method to get a callback
+        }
+
+        @DataClass.Generated.Member
+        public @NonNull String getBar() {
+            return mBar;
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public boolean equals(@android.annotation.Nullable Object o) {
+            // You can override field equality logic by defining either of the methods like:
+            // boolean fieldNameEquals(NestedDataClass other) { ... }
+            // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            @SuppressWarnings("unchecked")
+            NestedDataClass that = (NestedDataClass) o;
+            //noinspection PointlessBooleanExpression
+            return true
+                    && java.util.Objects.equals(mBar, that.mBar);
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public int hashCode() {
+            // You can override field hashCode logic by defining methods like:
+            // int fieldNameHashCode() { ... }
+
+            int _hash = 1;
+            _hash = 31 * _hash + java.util.Objects.hashCode(mBar);
+            return _hash;
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            // You can override field parcelling by defining methods like:
+            // void parcelFieldName(Parcel dest, int flags) { ... }
+
+            dest.writeString(mBar);
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public int describeContents() { return 0; }
+
+        /** @hide */
+        @SuppressWarnings({"unchecked", "RedundantCast"})
+        @DataClass.Generated.Member
+        protected NestedDataClass(@NonNull Parcel in) {
+            // You can override field unparcelling by defining methods like:
+            // static FieldType unparcelFieldName(Parcel in) { ... }
+
+            String bar = in.readString();
+
+            this.mBar = bar;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, mBar);
+
+            // onConstructed(); // You can define this method to get a callback
+        }
+
+        @DataClass.Generated.Member
+        public static final @NonNull Parcelable.Creator<NestedDataClass> CREATOR
+                = new Parcelable.Creator<NestedDataClass>() {
+            @Override
+            public NestedDataClass[] newArray(int size) {
+                return new NestedDataClass[size];
+            }
+
+            @Override
+            public NestedDataClass createFromParcel(@NonNull Parcel in) {
+                return new NestedDataClass(in);
+            }
+        };
+
+        @DataClass.Generated(
+                time = 1572655995915L,
+                codegenVersion = "1.0.12",
+                sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
+                inputSignatures = " @android.annotation.NonNull java.lang.String mBar\nclass NestedDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
+        @Deprecated
+        private void __metadata() {}
+
+
+        //@formatter:on
+        // End of generated code
+
+    }
+
+    @DataClass(genEqualsHashCode = true)
+    public static class NestedDataClass2 implements Parcelable {
+
+        @NonNull String mBaz;
+
+        @DataClass(genEqualsHashCode = true)
+        public static class NestedDataClass3 implements Parcelable {
+
+            @NonNull long mBaz2;
+
+
+
+            // Code below generated by codegen v1.0.12.
+            //
+            // DO NOT MODIFY!
+            // CHECKSTYLE:OFF Generated code
+            //
+            // To regenerate run:
+            // $ codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
+            //
+            // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+            //   Settings > Editor > Code Style > Formatter Control
+            //@formatter:off
+
+
+            @DataClass.Generated.Member
+            public NestedDataClass3(
+                    @NonNull long baz2) {
+                this.mBaz2 = baz2;
+                com.android.internal.util.AnnotationValidations.validate(
+                        NonNull.class, null, mBaz2);
+
+                // onConstructed(); // You can define this method to get a callback
+            }
+
+            @DataClass.Generated.Member
+            public @NonNull long getBaz2() {
+                return mBaz2;
+            }
+
+            @Override
+            @DataClass.Generated.Member
+            public boolean equals(@android.annotation.Nullable Object o) {
+                // You can override field equality logic by defining either of the methods like:
+                // boolean fieldNameEquals(NestedDataClass3 other) { ... }
+                // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+                if (this == o) return true;
+                if (o == null || getClass() != o.getClass()) return false;
+                @SuppressWarnings("unchecked")
+                NestedDataClass3 that = (NestedDataClass3) o;
+                //noinspection PointlessBooleanExpression
+                return true
+                        && mBaz2 == that.mBaz2;
+            }
+
+            @Override
+            @DataClass.Generated.Member
+            public int hashCode() {
+                // You can override field hashCode logic by defining methods like:
+                // int fieldNameHashCode() { ... }
+
+                int _hash = 1;
+                _hash = 31 * _hash + Long.hashCode(mBaz2);
+                return _hash;
+            }
+
+            @Override
+            @DataClass.Generated.Member
+            public void writeToParcel(@NonNull Parcel dest, int flags) {
+                // You can override field parcelling by defining methods like:
+                // void parcelFieldName(Parcel dest, int flags) { ... }
+
+                dest.writeLong(mBaz2);
+            }
+
+            @Override
+            @DataClass.Generated.Member
+            public int describeContents() { return 0; }
+
+            /** @hide */
+            @SuppressWarnings({"unchecked", "RedundantCast"})
+            @DataClass.Generated.Member
+            protected NestedDataClass3(@NonNull Parcel in) {
+                // You can override field unparcelling by defining methods like:
+                // static FieldType unparcelFieldName(Parcel in) { ... }
+
+                long baz2 = in.readLong();
+
+                this.mBaz2 = baz2;
+                com.android.internal.util.AnnotationValidations.validate(
+                        NonNull.class, null, mBaz2);
+
+                // onConstructed(); // You can define this method to get a callback
+            }
+
+            @DataClass.Generated.Member
+            public static final @NonNull Parcelable.Creator<NestedDataClass3> CREATOR
+                    = new Parcelable.Creator<NestedDataClass3>() {
+                @Override
+                public NestedDataClass3[] newArray(int size) {
+                    return new NestedDataClass3[size];
+                }
+
+                @Override
+                public NestedDataClass3 createFromParcel(@NonNull Parcel in) {
+                    return new NestedDataClass3(in);
+                }
+            };
+
+            @DataClass.Generated(
+                    time = 1572655995924L,
+                    codegenVersion = "1.0.12",
+                    sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
+                    inputSignatures = " @android.annotation.NonNull long mBaz2\nclass NestedDataClass3 extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
+            @Deprecated
+            private void __metadata() {}
+
+
+            //@formatter:on
+            // End of generated code
+
+        }
+
+
+
+        // Code below generated by codegen v1.0.12.
+        //
+        // DO NOT MODIFY!
+        // CHECKSTYLE:OFF Generated code
+        //
+        // To regenerate run:
+        // $ codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java
+        //
+        // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+        //   Settings > Editor > Code Style > Formatter Control
+        //@formatter:off
+
+
+        @DataClass.Generated.Member
+        public NestedDataClass2(
+                @NonNull String baz) {
+            this.mBaz = baz;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, mBaz);
+
+            // onConstructed(); // You can define this method to get a callback
+        }
+
+        @DataClass.Generated.Member
+        public @NonNull String getBaz() {
+            return mBaz;
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public boolean equals(@android.annotation.Nullable Object o) {
+            // You can override field equality logic by defining either of the methods like:
+            // boolean fieldNameEquals(NestedDataClass2 other) { ... }
+            // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            @SuppressWarnings("unchecked")
+            NestedDataClass2 that = (NestedDataClass2) o;
+            //noinspection PointlessBooleanExpression
+            return true
+                    && java.util.Objects.equals(mBaz, that.mBaz);
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public int hashCode() {
+            // You can override field hashCode logic by defining methods like:
+            // int fieldNameHashCode() { ... }
+
+            int _hash = 1;
+            _hash = 31 * _hash + java.util.Objects.hashCode(mBaz);
+            return _hash;
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            // You can override field parcelling by defining methods like:
+            // void parcelFieldName(Parcel dest, int flags) { ... }
+
+            dest.writeString(mBaz);
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public int describeContents() { return 0; }
+
+        /** @hide */
+        @SuppressWarnings({"unchecked", "RedundantCast"})
+        @DataClass.Generated.Member
+        protected NestedDataClass2(@NonNull Parcel in) {
+            // You can override field unparcelling by defining methods like:
+            // static FieldType unparcelFieldName(Parcel in) { ... }
+
+            String baz = in.readString();
+
+            this.mBaz = baz;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, mBaz);
+
+            // onConstructed(); // You can define this method to get a callback
+        }
+
+        @DataClass.Generated.Member
+        public static final @NonNull Parcelable.Creator<NestedDataClass2> CREATOR
+                = new Parcelable.Creator<NestedDataClass2>() {
+            @Override
+            public NestedDataClass2[] newArray(int size) {
+                return new NestedDataClass2[size];
+            }
+
+            @Override
+            public NestedDataClass2 createFromParcel(@NonNull Parcel in) {
+                return new NestedDataClass2(in);
+            }
+        };
+
+        @DataClass.Generated(
+                time = 1572655995930L,
+                codegenVersion = "1.0.12",
+                sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithNestedDataClasses.java",
+                inputSignatures = " @android.annotation.NonNull java.lang.String mBaz\nclass NestedDataClass2 extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
+        @Deprecated
+        private void __metadata() {}
+
+
+        //@formatter:on
+        // End of generated code
+
+    }
+
+    void someCode() {}
+}
diff --git a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
index b967f19..4bfec89 100644
--- a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
+++ b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
@@ -51,7 +51,7 @@
 
 
 
-    // Code below generated by codegen v1.0.9.
+    // Code below generated by codegen v1.0.12.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -65,11 +65,15 @@
 
 
     @DataClass.Generated(
-            time = 1571258916868L,
-            codegenVersion = "1.0.9",
+            time = 1572655994865L,
+            codegenVersion = "1.0.12",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java",
             inputSignatures = "public @android.annotation.NonNull java.lang.String someMethod(int)\nclass StaleDataclassDetectorFalsePositivesTest extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false)")
     @Deprecated
     private void __metadata() {}
 
+
+    //@formatter:on
+    // End of generated code
+
 }
diff --git a/tests/Compatibility/Android.bp b/tests/Compatibility/Android.bp
index 4ca406e..7dc44fa 100644
--- a/tests/Compatibility/Android.bp
+++ b/tests/Compatibility/Android.bp
@@ -19,4 +19,7 @@
     srcs: ["src/**/*.java"],
     platform_apis: true,
     certificate: "platform",
+    test_suites: [
+        "csuite"
+    ],
 }
diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp
index 085c53c..2bc129a 100644
--- a/tests/RollbackTest/Android.bp
+++ b/tests/RollbackTest/Android.bp
@@ -25,6 +25,7 @@
     name: "StagedRollbackTest",
     srcs: ["StagedRollbackTest/src/**/*.java"],
     libs: ["tradefed"],
+    static_libs: ["testng"],
     test_suites: ["general-tests"],
     test_config: "StagedRollbackTest.xml",
 }
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index f06b18a..8b01930 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -30,8 +30,10 @@
 import android.content.Intent;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
 import android.content.rollback.RollbackInfo;
 import android.content.rollback.RollbackManager;
+import android.os.ParcelFileDescriptor;
 import android.provider.DeviceConfig;
 import android.text.TextUtils;
 
@@ -46,12 +48,17 @@
 import com.android.cts.rollback.lib.RollbackUtils;
 import com.android.internal.R;
 
+import libcore.io.IoUtils;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+import java.io.File;
+import java.util.concurrent.TimeUnit;
+
 /**
  * Tests for rollback of staged installs.
  * <p>
@@ -67,8 +74,13 @@
             "android.net.INetworkStackConnector";
     private static final String PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT =
             "watchdog_trigger_failure_count";
+    private static final String PROPERTY_WATCHDOG_REQUEST_TIMEOUT_MILLIS =
+            "watchdog_request_timeout_millis";
 
     private static final String MODULE_META_DATA_PACKAGE = getModuleMetadataPackageName();
+    private static final TestApp NETWORK_STACK = new TestApp("NetworkStack",
+            getNetworkStackPackageName(), -1, false,
+            new File("/system/priv-app/NetworkStack/NetworkStack.apk"));
 
     /**
      * Adopts common shell permissions needed for rollback tests.
@@ -123,6 +135,13 @@
         assertThat(rollback).packagesContainsExactly(
                 Rollback.from(TestApp.A2).to(TestApp.A1));
         assertThat(rollback.isStaged()).isTrue();
+
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+                PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
+                Integer.toString(5), false);
+        RollbackUtils.sendCrashBroadcast(TestApp.A, 4);
+        // Sleep for a while to make sure we don't trigger rollback
+        Thread.sleep(TimeUnit.SECONDS.toMillis(30));
     }
 
     /**
@@ -132,11 +151,8 @@
      */
     @Test
     public void testBadApkOnly_Phase3() throws Exception {
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
-                PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
-                Integer.toString(5), false);
-
-        RollbackUtils.sendCrashBroadcast(TestApp.A, 5);
+        // One more crash to trigger rollback
+        RollbackUtils.sendCrashBroadcast(TestApp.A, 1);
 
         // We expect the device to be rebooted automatically. Wait for that to happen.
         Thread.sleep(30 * 1000);
@@ -205,14 +221,22 @@
 
     @Test
     public void testNetworkFailedRollback_Phase1() throws Exception {
+        // Remove available rollbacks and uninstall NetworkStack on /data/
         RollbackManager rm = RollbackUtils.getRollbackManager();
         String networkStack = getNetworkStackPackageName();
 
         rm.expireRollbackForPackage(networkStack);
-        Uninstall.packages(networkStack);
+        uninstallNetworkStackPackage();
 
         assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
                         networkStack)).isNull();
+
+        // Reduce health check deadline
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+                PROPERTY_WATCHDOG_REQUEST_TIMEOUT_MILLIS,
+                Integer.toString(120000), false);
+        // Simulate re-installation of new NetworkStack with rollbacks enabled
+        installNetworkStackPackage();
     }
 
     @Test
@@ -220,13 +244,21 @@
         RollbackManager rm = RollbackUtils.getRollbackManager();
         assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
                         getNetworkStackPackageName())).isNotNull();
+
+        // Sleep for < health check deadline
+        Thread.sleep(TimeUnit.SECONDS.toMillis(5));
+        // Verify rollback was not executed before health check deadline
+        assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
+                        getNetworkStackPackageName())).isNull();
     }
 
     @Test
     public void testNetworkFailedRollback_Phase3() throws Exception {
-        RollbackManager rm = RollbackUtils.getRollbackManager();
-        assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
-                        getNetworkStackPackageName())).isNull();
+        // Sleep for > health check deadline
+        // The device is expected to reboot during sleeping. This device method will fail and
+        // the host will catch the assertion. If reboot doesn't happen, the host will fail the
+        // assertion.
+        Thread.sleep(TimeUnit.SECONDS.toMillis(120));
     }
 
     @Test
@@ -236,13 +268,23 @@
                         getNetworkStackPackageName())).isNotNull();
     }
 
-    private String getNetworkStackPackageName() {
+    private static String getNetworkStackPackageName() {
         Intent intent = new Intent(NETWORK_STACK_CONNECTOR_CLASS);
         ComponentName comp = intent.resolveSystemService(
                 InstrumentationRegistry.getContext().getPackageManager(), 0);
         return comp.getPackageName();
     }
 
+    private static void installNetworkStackPackage() throws Exception {
+        Install.single(NETWORK_STACK).setStaged().setEnableRollback()
+                .addInstallFlags(PackageManager.INSTALL_REPLACE_EXISTING).commit();
+    }
+
+    private static void uninstallNetworkStackPackage() {
+        // Uninstall the package as a privileged user so we won't fail due to permission.
+        runShellCommand("pm uninstall " + getNetworkStackPackageName());
+    }
+
     @Test
     public void testPreviouslyAbandonedRollbacks_Phase1() throws Exception {
         Uninstall.packages(TestApp.A);
@@ -285,7 +327,7 @@
         String networkStack = getNetworkStackPackageName();
 
         rm.expireRollbackForPackage(networkStack);
-        Uninstall.packages(networkStack);
+        uninstallNetworkStackPackage();
 
         assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
                         networkStack)).isNull();
@@ -325,8 +367,9 @@
                 MODULE_META_DATA_PACKAGE)).isNull();
     }
 
-    private void runShellCommand(String cmd) {
-        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+    private static void runShellCommand(String cmd) {
+        ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation().getUiAutomation()
                 .executeShellCommand(cmd);
+        IoUtils.closeQuietly(pfd);
     }
 }
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 57f211d..18a813d 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -17,14 +17,14 @@
 package com.android.tests.rollback.host;
 
 import static org.junit.Assert.assertTrue;
+import static org.testng.Assert.assertThrows;
 
 import com.android.ddmlib.Log.LogLevel;
 import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
-import org.junit.After;
-import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -49,20 +49,6 @@
                     phase));
     }
 
-    @Before
-    public void setUp() throws Exception {
-        // Disconnect internet so we can test network health triggered rollbacks
-        getDevice().executeShellCommand("svc wifi disable");
-        getDevice().executeShellCommand("svc data disable");
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        // Reconnect internet after testing network health triggered rollbacks
-        getDevice().executeShellCommand("svc wifi enable");
-        getDevice().executeShellCommand("svc data enable");
-    }
-
     /**
      * Tests watchdog triggered staged rollbacks involving only apks.
      */
@@ -94,7 +80,6 @@
 
         // Reboot device to activate staged package
         getDevice().reboot();
-        getDevice().waitForDeviceAvailable();
 
         runPhase("testNativeWatchdogTriggersRollback_Phase2");
 
@@ -121,49 +106,34 @@
      */
     @Test
     public void testNetworkFailedRollback() throws Exception {
-        // Remove available rollbacks and uninstall NetworkStack on /data/
-        runPhase("testNetworkFailedRollback_Phase1");
-        // Reduce health check deadline
-        getDevice().executeShellCommand("device_config put rollback "
-                + "watchdog_request_timeout_millis 300000");
-        // Simulate re-installation of new NetworkStack with rollbacks enabled
-        getDevice().executeShellCommand("pm install -r --staged --enable-rollback "
-                + "/system/priv-app/NetworkStack/NetworkStack.apk");
-
-        // Sleep to allow writes to disk before reboot
-        Thread.sleep(5000);
-        // Reboot device to activate staged package
-        getDevice().reboot();
-        getDevice().waitForDeviceAvailable();
-
-        // Verify rollback was enabled
-        runPhase("testNetworkFailedRollback_Phase2");
-
-        // Sleep for < health check deadline
-        Thread.sleep(5000);
-        // Verify rollback was not executed before health check deadline
-        runPhase("testNetworkFailedRollback_Phase3");
         try {
-            // This is expected to fail due to the device being rebooted out
-            // from underneath the test. If this fails for reasons other than
-            // the device reboot, those failures should result in failure of
-            // the testNetworkFailedRollback_Phase4 phase.
-            CLog.logAndDisplay(LogLevel.INFO, "Sleep and expect to fail while sleeping");
-            // Sleep for > health check deadline
-            Thread.sleep(260000);
-        } catch (AssertionError e) {
-            // AssertionError is expected.
-        }
+            // Disconnect internet so we can test network health triggered rollbacks
+            getDevice().executeShellCommand("svc wifi disable");
+            getDevice().executeShellCommand("svc data disable");
 
-        getDevice().waitForDeviceAvailable();
-        // Verify rollback was executed after health check deadline
-        runPhase("testNetworkFailedRollback_Phase4");
+            runPhase("testNetworkFailedRollback_Phase1");
+            // Reboot device to activate staged package
+            getDevice().reboot();
+
+            // Verify rollback was enabled
+            runPhase("testNetworkFailedRollback_Phase2");
+            assertThrows(AssertionError.class, () -> runPhase("testNetworkFailedRollback_Phase3"));
+
+            getDevice().waitForDeviceAvailable();
+            // Verify rollback was executed after health check deadline
+            runPhase("testNetworkFailedRollback_Phase4");
+        } finally {
+            // Reconnect internet again so we won't break tests which assume internet available
+            getDevice().executeShellCommand("svc wifi enable");
+            getDevice().executeShellCommand("svc data enable");
+        }
     }
 
     /**
      * Tests passed network health check does not trigger watchdog staged rollbacks.
      */
     @Test
+    @Ignore("b/143514090")
     public void testNetworkPassedDoesNotRollback() throws Exception {
         // Remove available rollbacks and uninstall NetworkStack on /data/
         runPhase("testNetworkPassedDoesNotRollback_Phase1");
@@ -180,7 +150,6 @@
         Thread.sleep(5000);
         // Reboot device to activate staged package
         getDevice().reboot();
-        getDevice().waitForDeviceAvailable();
 
         // Verify rollback was enabled
         runPhase("testNetworkPassedDoesNotRollback_Phase2");
diff --git a/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java b/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java
index ba77a74..1664746 100644
--- a/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java
+++ b/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java
@@ -73,6 +73,10 @@
         mFps = 0;
         mLastFpsUpdate = 0;
         mFrameCount = 0;
+
+        mDf = new DecimalFormat("fps: #.##");
+        mDf.setRoundingMode(RoundingMode.HALF_UP);
+
         Trace.endSection();
     }
 
@@ -181,9 +185,7 @@
         // Draw the ball
         canvas.drawColor(BACKGROUND_COLOR);
         canvas.drawOval(left, top, right, bottom, getBallColor());
-        DecimalFormat df = new DecimalFormat("fps: #.##");
-        df.setRoundingMode(RoundingMode.HALF_UP);
-        canvas.drawText(df.format(mFps), width, 100, mTextPaint);
+        canvas.drawText(mDf.format(mFps), width, 100, mTextPaint);
 
         invalidate();
         Trace.endSection();
@@ -220,6 +222,7 @@
 
     private long mLastDrawNano, mLastFpsUpdate, mFrameCount;
     private float mFps;
+    private DecimalFormat mDf;
 }
 
 public class TouchLatencyActivity extends Activity {
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index beb5e0d..10f27e2 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -37,14 +37,18 @@
         "libvndksupport",
         "libziparchive",
         "libz",
-        "netd_aidl_interface-V2-cpp",
+        "netd_aidl_interface-cpp",
     ],
 }
 
 android_test {
     name: "FrameworksNetTests",
     defaults: ["FrameworksNetTests-jni-defaults"],
-    srcs: ["java/**/*.java", "java/**/*.kt"],
+    srcs: [
+        ":tethering-tests-src",
+        "java/**/*.java",
+        "java/**/*.kt",
+    ],
     platform_apis: true,
     test_suites: ["device-tests"],
     certificate: "platform",
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 2ca0d1a..1569112 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -271,7 +271,7 @@
             .addCapability(NET_CAPABILITY_NOT_METERED);
         assertParcelingIsLossless(netCap);
         netCap.setSSID(TEST_SSID);
-        assertParcelSane(netCap, 11);
+        assertParcelSane(netCap, 12);
     }
 
     @Test
diff --git a/tests/net/java/android/net/netlink/InetDiagSocketTest.java b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
index 46e27c1..1f2bb0a 100644
--- a/tests/net/java/android/net/netlink/InetDiagSocketTest.java
+++ b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
@@ -30,6 +30,7 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.app.Instrumentation;
 import android.content.Context;
@@ -283,6 +284,107 @@
         assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg);
     }
 
+    // Hexadecimal representation of InetDiagReqV2 request with extension, INET_DIAG_INFO.
+    private static final String INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_HEX =
+            // struct nlmsghdr
+            "48000000" +     // length = 72
+            "1400" +         // type = SOCK_DIAG_BY_FAMILY
+            "0100" +         // flags = NLM_F_REQUEST
+            "00000000" +     // seqno
+            "00000000" +     // pid (0 == kernel)
+            // struct inet_diag_req_v2
+            "02" +           // family = AF_INET
+            "06" +           // protcol = IPPROTO_TCP
+            "02" +           // idiag_ext = INET_DIAG_INFO
+            "00" +           // pad
+            "ffffffff" +   // idiag_states
+            // inet_diag_sockid
+            "3039" +         // idiag_sport = 12345
+            "d431" +         // idiag_dport = 54321
+            "01020304000000000000000000000000" + // idiag_src = 1.2.3.4
+            "08080404000000000000000000000000" + // idiag_dst = 8.8.4.4
+            "00000000" +     // idiag_if
+            "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE
+
+    private static final byte[] INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_BYTES =
+            HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_HEX.toCharArray(), false);
+    private static final int TCP_ALL_STATES = 0xffffffff;
+    @Test
+    public void testInetDiagReqV2TcpInetWithExt() throws Exception {
+        InetSocketAddress local = new InetSocketAddress(
+                InetAddress.getByName("1.2.3.4"), 12345);
+        InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.4.4"),
+                54321);
+        byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET,
+                NLM_F_REQUEST, 0 /* pad */, 2 /* idiagExt */, TCP_ALL_STATES);
+
+        assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_BYTES, msg);
+
+        local = new InetSocketAddress(
+                InetAddress.getByName("fe80::86c9:b2ff:fe6a:ed4b"), 42462);
+        remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"),
+                47473);
+        msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET6,
+                NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
+
+        assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg);
+    }
+
+    // Hexadecimal representation of InetDiagReqV2 request with no socket specified.
+    private static final String INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_HEX =
+            // struct nlmsghdr
+            "48000000" +     // length = 72
+            "1400" +         // type = SOCK_DIAG_BY_FAMILY
+            "0100" +         // flags = NLM_F_REQUEST
+            "00000000" +     // seqno
+            "00000000" +     // pid (0 == kernel)
+            // struct inet_diag_req_v2
+            "0a" +           // family = AF_INET6
+            "06" +           // protcol = IPPROTO_TCP
+            "00" +           // idiag_ext
+            "00" +           // pad
+            "ffffffff" +     // idiag_states
+            // inet_diag_sockid
+            "0000" +         // idiag_sport
+            "0000" +         // idiag_dport
+            "00000000000000000000000000000000" + // idiag_src
+            "00000000000000000000000000000000" + // idiag_dst
+            "00000000" +     // idiag_if
+            "0000000000000000"; // idiag_cookie
+
+    private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES =
+            HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_HEX.toCharArray(), false);
+
+    @Test
+    public void testInetDiagReqV2TcpInet6NoIdSpecified() throws Exception {
+        InetSocketAddress local = new InetSocketAddress(
+                InetAddress.getByName("fe80::fe6a:ed4b"), 12345);
+        InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.4.4"),
+                54321);
+        // Verify no socket specified if either local or remote socket address is null.
+        byte[] msgExt = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, null, AF_INET6,
+                NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
+        byte[] msg;
+        try {
+            msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, remote, AF_INET6,
+                    NLM_F_REQUEST);
+            fail("Both remote and local should be null, expected UnknownHostException");
+        } catch (NullPointerException e) {
+        }
+
+        try {
+            msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, null, AF_INET6,
+                    NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
+            fail("Both remote and local should be null, expected UnknownHostException");
+        } catch (NullPointerException e) {
+        }
+
+        msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, null, AF_INET6,
+                NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES);
+        assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES, msg);
+        assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES, msgExt);
+    }
+
     // Hexadecimal representation of InetDiagReqV2 request.
     private static final String INET_DIAG_MSG_HEX =
             // struct nlmsghdr
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index cf3fba8..61f37fd 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -33,6 +33,7 @@
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTPS;
+import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
 import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
@@ -492,6 +493,8 @@
         private INetworkMonitor mNetworkMonitor;
         private INetworkMonitorCallbacks mNmCallbacks;
         private int mNmValidationResult = VALIDATION_RESULT_BASE;
+        private int mProbesCompleted;
+        private int mProbesSucceeded;
         private String mNmValidationRedirectUrl = null;
         private boolean mNmProvNotificationRequested = false;
 
@@ -559,6 +562,7 @@
                 mNmProvNotificationRequested = false;
             }
 
+            mNmCallbacks.notifyProbeStatusChanged(mProbesCompleted, mProbesSucceeded);
             mNmCallbacks.notifyNetworkTested(
                     mNmValidationResult, mNmValidationRedirectUrl);
 
@@ -581,7 +585,7 @@
          * @param validated Indicate if network should pretend to be validated.
          */
         public void connect(boolean validated) {
-            connect(validated, true);
+            connect(validated, true, false /* isStrictMode */);
         }
 
         /**
@@ -589,13 +593,13 @@
          * @param validated Indicate if network should pretend to be validated.
          * @param hasInternet Indicate if network should pretend to have NET_CAPABILITY_INTERNET.
          */
-        public void connect(boolean validated, boolean hasInternet) {
+        public void connect(boolean validated, boolean hasInternet, boolean isStrictMode) {
             assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_INTERNET));
 
             ConnectivityManager.NetworkCallback callback = null;
             final ConditionVariable validatedCv = new ConditionVariable();
             if (validated) {
-                setNetworkValid();
+                setNetworkValid(isStrictMode);
                 NetworkRequest request = new NetworkRequest.Builder()
                         .addTransportType(getNetworkCapabilities().getTransportTypes()[0])
                         .clearCapabilities()
@@ -620,15 +624,15 @@
             if (validated) {
                 // Wait for network to validate.
                 waitFor(validatedCv);
-                setNetworkInvalid();
+                setNetworkInvalid(isStrictMode);
             }
 
             if (callback != null) mCm.unregisterNetworkCallback(callback);
         }
 
-        public void connectWithCaptivePortal(String redirectUrl) {
-            setNetworkPortal(redirectUrl);
-            connect(false);
+        public void connectWithCaptivePortal(String redirectUrl, boolean isStrictMode) {
+            setNetworkPortal(redirectUrl, isStrictMode);
+            connect(false, true /* hasInternet */, isStrictMode);
         }
 
         public void connectWithPartialConnectivity() {
@@ -636,34 +640,75 @@
             connect(false);
         }
 
-        public void connectWithPartialValidConnectivity() {
-            setNetworkPartialValid();
-            connect(false);
+        public void connectWithPartialValidConnectivity(boolean isStrictMode) {
+            setNetworkPartialValid(isStrictMode);
+            connect(false, true /* hasInternet */, isStrictMode);
         }
 
-        void setNetworkValid() {
+        void setNetworkValid(boolean isStrictMode) {
             mNmValidationResult = VALIDATION_RESULT_VALID;
             mNmValidationRedirectUrl = null;
+            int probesSucceeded = VALIDATION_RESULT_BASE & ~NETWORK_VALIDATION_PROBE_HTTP;
+            if (isStrictMode) {
+                probesSucceeded |= NETWORK_VALIDATION_PROBE_PRIVDNS;
+            }
+            // The probesCompleted equals to probesSucceeded for the case of valid network, so put
+            // the same value into two different parameter of the method.
+            setProbesStatus(probesSucceeded, probesSucceeded);
         }
 
-        void setNetworkInvalid() {
+        void setNetworkInvalid(boolean isStrictMode) {
             mNmValidationResult = VALIDATION_RESULT_INVALID;
             mNmValidationRedirectUrl = null;
+            int probesCompleted = VALIDATION_RESULT_BASE;
+            int probesSucceeded = VALIDATION_RESULT_INVALID;
+            // If the isStrictMode is true, it means the network is invalid when NetworkMonitor
+            // tried to validate the private DNS but failed.
+            if (isStrictMode) {
+                probesCompleted &= ~NETWORK_VALIDATION_PROBE_HTTP;
+                probesSucceeded = probesCompleted;
+                probesCompleted |= NETWORK_VALIDATION_PROBE_PRIVDNS;
+            }
+            setProbesStatus(probesCompleted, probesSucceeded);
         }
 
-        void setNetworkPortal(String redirectUrl) {
-            setNetworkInvalid();
+        void setNetworkPortal(String redirectUrl, boolean isStrictMode) {
+            setNetworkInvalid(isStrictMode);
             mNmValidationRedirectUrl = redirectUrl;
+            // Suppose the portal is found when NetworkMonitor probes NETWORK_VALIDATION_PROBE_HTTP
+            // in the beginning, so the NETWORK_VALIDATION_PROBE_HTTPS hasn't probed yet.
+            int probesCompleted = VALIDATION_RESULT_BASE & ~NETWORK_VALIDATION_PROBE_HTTPS;
+            int probesSucceeded = VALIDATION_RESULT_INVALID;
+            if (isStrictMode) {
+                probesCompleted |= NETWORK_VALIDATION_PROBE_PRIVDNS;
+            }
+            setProbesStatus(probesCompleted, probesSucceeded);
         }
 
         void setNetworkPartial() {
             mNmValidationResult = VALIDATION_RESULT_PARTIAL;
             mNmValidationRedirectUrl = null;
+            int probesCompleted = VALIDATION_RESULT_BASE;
+            int probesSucceeded = VALIDATION_RESULT_BASE & ~NETWORK_VALIDATION_PROBE_HTTPS;
+            setProbesStatus(probesCompleted, probesSucceeded);
         }
 
-        void setNetworkPartialValid() {
-            mNmValidationResult = VALIDATION_RESULT_PARTIAL | VALIDATION_RESULT_VALID;
-            mNmValidationRedirectUrl = null;
+        void setNetworkPartialValid(boolean isStrictMode) {
+            setNetworkPartial();
+            mNmValidationResult |= VALIDATION_RESULT_VALID;
+            int probesCompleted = VALIDATION_RESULT_BASE;
+            int probesSucceeded = VALIDATION_RESULT_BASE & ~NETWORK_VALIDATION_PROBE_HTTPS;
+            // Suppose the partial network cannot pass the private DNS validation as well, so only
+            // add NETWORK_VALIDATION_PROBE_DNS in probesCompleted but not probesSucceeded.
+            if (isStrictMode) {
+                probesCompleted |= NETWORK_VALIDATION_PROBE_PRIVDNS;
+            }
+            setProbesStatus(probesCompleted, probesSucceeded);
+        }
+
+        void setProbesStatus(int probesCompleted, int probesSucceeded) {
+            mProbesCompleted = probesCompleted;
+            mProbesSucceeded = probesSucceeded;
         }
 
         public String waitForRedirectUrl() {
@@ -2226,7 +2271,7 @@
 
         // With HTTPS probe disabled, NetworkMonitor should pass the network validation with http
         // probe.
-        mWiFiNetworkAgent.setNetworkPartialValid();
+        mWiFiNetworkAgent.setNetworkPartialValid(false /* isStrictMode */);
         // If the user chooses yes to use this partial connectivity wifi, switch the default
         // network to wifi and check if wifi becomes valid or not.
         mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), true /* accept */,
@@ -2299,7 +2344,7 @@
         callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
         callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
-        mWiFiNetworkAgent.setNetworkValid();
+        mWiFiNetworkAgent.setNetworkValid(false /* isStrictMode */);
 
         // Need a trigger point to let NetworkMonitor tell ConnectivityService that network is
         // validated.
@@ -2317,7 +2362,7 @@
         // NetworkMonitor will immediately (once the HTTPS probe fails...) report the network as
         // valid, because ConnectivityService calls setAcceptPartialConnectivity before it calls
         // notifyNetworkConnected.
-        mWiFiNetworkAgent.connectWithPartialValidConnectivity();
+        mWiFiNetworkAgent.connectWithPartialValidConnectivity(false /* isStrictMode */);
         callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
         callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
@@ -2343,7 +2388,7 @@
         // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         String redirectUrl = "http://android.com/path";
-        mWiFiNetworkAgent.connectWithCaptivePortal(redirectUrl);
+        mWiFiNetworkAgent.connectWithCaptivePortal(redirectUrl, false /* isStrictMode */);
         captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), redirectUrl);
 
@@ -2361,7 +2406,7 @@
                 mWiFiNetworkAgent);
 
         // Report partial connectivity is accepted.
-        mWiFiNetworkAgent.setNetworkPartialValid();
+        mWiFiNetworkAgent.setNetworkPartialValid(false /* isStrictMode */);
         mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), true /* accept */,
                 false /* always */);
         waitForIdle();
@@ -2392,7 +2437,7 @@
         // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         String firstRedirectUrl = "http://example.com/firstPath";
-        mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
+        mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl, false /* isStrictMode */);
         captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), firstRedirectUrl);
 
@@ -2405,13 +2450,13 @@
         // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         String secondRedirectUrl = "http://example.com/secondPath";
-        mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
+        mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl, false /* isStrictMode */);
         captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), secondRedirectUrl);
 
         // Make captive portal disappear then revalidate.
         // Expect onLost callback because network no longer provides NET_CAPABILITY_CAPTIVE_PORTAL.
-        mWiFiNetworkAgent.setNetworkValid();
+        mWiFiNetworkAgent.setNetworkValid(false /* isStrictMode */);
         mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
         captivePortalCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
 
@@ -2423,7 +2468,7 @@
 
         // Break network connectivity.
         // Expect NET_CAPABILITY_VALIDATED onLost callback.
-        mWiFiNetworkAgent.setNetworkInvalid();
+        mWiFiNetworkAgent.setNetworkInvalid(false /* isStrictMode */);
         mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
         validatedCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
     }
@@ -2454,7 +2499,7 @@
         mServiceContext.expectNoStartActivityIntent(fastTimeoutMs);
 
         // Turn into a captive portal.
-        mWiFiNetworkAgent.setNetworkPortal("http://example.com");
+        mWiFiNetworkAgent.setNetworkPortal("http://example.com", false /* isStrictMode */);
         mCm.reportNetworkConnectivity(wifiNetwork, false);
         captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
         validatedCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
@@ -2475,7 +2520,7 @@
         assertEquals(testValue, signInIntent.getStringExtra(testKey));
 
         // Report that the captive portal is dismissed, and check that callbacks are fired
-        mWiFiNetworkAgent.setNetworkValid();
+        mWiFiNetworkAgent.setNetworkValid(false /* isStrictMode */);
         mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
         validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
         captivePortalCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
@@ -2504,7 +2549,7 @@
         mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
         String firstRedirectUrl = "http://example.com/firstPath";
 
-        mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
+        mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl, false /* isStrictMode */);
         mWiFiNetworkAgent.expectDisconnected();
         mWiFiNetworkAgent.expectPreventReconnectReceived();
 
@@ -3219,7 +3264,7 @@
         Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
 
         // Fail validation on wifi.
-        mWiFiNetworkAgent.setNetworkInvalid();
+        mWiFiNetworkAgent.setNetworkInvalid(false /* isStrictMode */);
         mCm.reportNetworkConnectivity(wifiNetwork, false);
         defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
         validatedWifiCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
@@ -3263,7 +3308,7 @@
         wifiNetwork = mWiFiNetworkAgent.getNetwork();
 
         // Fail validation on wifi and expect the dialog to appear.
-        mWiFiNetworkAgent.setNetworkInvalid();
+        mWiFiNetworkAgent.setNetworkInvalid(false /* isStrictMode */);
         mCm.reportNetworkConnectivity(wifiNetwork, false);
         defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
         validatedWifiCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
@@ -4299,7 +4344,7 @@
         mCm.registerNetworkCallback(request, callback);
 
         // Bring up wifi aware network.
-        wifiAware.connect(false, false);
+        wifiAware.connect(false, false, false /* isStrictMode */);
         callback.expectAvailableCallbacksUnvalidated(wifiAware);
 
         assertNull(mCm.getActiveNetworkInfo());
@@ -4537,6 +4582,44 @@
     }
 
     @Test
+    public void testPrivateDnsNotification() throws Exception {
+        NetworkRequest request = new NetworkRequest.Builder()
+                .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
+                .build();
+        TestNetworkCallback callback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(request, callback);
+        // Bring up wifi.
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(false);
+        callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+        // Private DNS resolution failed, checking if the notification will be shown or not.
+        mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */);
+        mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
+        waitForIdle();
+        // If network validation failed, NetworkMonitor will re-evaluate the network.
+        // ConnectivityService should filter the redundant notification. This part is trying to
+        // simulate that situation and check if ConnectivityService could filter that case.
+        mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
+        waitForIdle();
+        verify(mNotificationManager, timeout(TIMEOUT_MS).times(1)).notifyAsUser(anyString(),
+                eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), any(), eq(UserHandle.ALL));
+        // If private DNS resolution successful, the PRIVATE_DNS_BROKEN notification shouldn't be
+        // shown.
+        mWiFiNetworkAgent.setNetworkValid(true /* isStrictMode */);
+        mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
+        waitForIdle();
+        verify(mNotificationManager, timeout(TIMEOUT_MS).times(1)).cancelAsUser(anyString(),
+                eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), eq(UserHandle.ALL));
+        // If private DNS resolution failed again, the PRIVATE_DNS_BROKEN notification should be
+        // shown again.
+        mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */);
+        mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
+        waitForIdle();
+        verify(mNotificationManager, timeout(TIMEOUT_MS).times(2)).notifyAsUser(anyString(),
+                eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), any(), eq(UserHandle.ALL));
+    }
+
+    @Test
     public void testPrivateDnsSettingsChange() throws Exception {
         // Clear any interactions that occur as a result of CS starting up.
         reset(mMockDnsResolver);
@@ -4793,7 +4876,7 @@
         // by NetworkMonitor
         assertFalse(NetworkMonitorUtils.isValidationRequired(
                 vpnNetworkAgent.getNetworkCapabilities()));
-        vpnNetworkAgent.setNetworkValid();
+        vpnNetworkAgent.setNetworkValid(false /* isStrictMode */);
 
         vpnNetworkAgent.connect(false);
         mMockVpn.connect();
@@ -4882,7 +4965,8 @@
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
         mMockVpn.setUids(ranges);
-        vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */);
+        vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */,
+                false /* isStrictMode */);
         mMockVpn.connect();
 
         defaultCallback.assertNoCallback();
@@ -4913,7 +4997,8 @@
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
         mMockVpn.setUids(ranges);
-        vpnNetworkAgent.connect(true /* validated */, true /* hasInternet */);
+        vpnNetworkAgent.connect(true /* validated */, true /* hasInternet */,
+                false /* isStrictMode */);
         mMockVpn.connect();
 
         defaultCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
@@ -4945,7 +5030,8 @@
         ranges.add(new UidRange(uid, uid));
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
         mMockVpn.setUids(ranges);
-        vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */);
+        vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */,
+                false /* isStrictMode */);
         mMockVpn.connect();
 
         // Even though the VPN is unvalidated, it becomes the default network for our app.
@@ -4968,7 +5054,7 @@
                 vpnNetworkAgent.getNetworkCapabilities()));
 
         // Pretend that the VPN network validates.
-        vpnNetworkAgent.setNetworkValid();
+        vpnNetworkAgent.setNetworkValid(false /* isStrictMode */);
         vpnNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
         // Expect to see the validated capability, but no other changes, because the VPN is already
         // the default network for the app.
@@ -5000,7 +5086,8 @@
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
         mMockVpn.connect();
         mMockVpn.setUids(ranges);
-        vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */);
+        vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */,
+                false /* isStrictMode */);
 
         vpnNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
         nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork());
@@ -5099,7 +5186,8 @@
         mMockVpn.setNetworkAgent(vpnNetworkAgent);
         mMockVpn.connect();
         mMockVpn.setUids(ranges);
-        vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */);
+        vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */,
+                false /* isStrictMode */);
 
         vpnNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
         nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork());
diff --git a/tests/testables/src/android/testing/TestableSettingsProvider.java b/tests/testables/src/android/testing/TestableSettingsProvider.java
index b158476..fd92c65 100644
--- a/tests/testables/src/android/testing/TestableSettingsProvider.java
+++ b/tests/testables/src/android/testing/TestableSettingsProvider.java
@@ -14,6 +14,8 @@
 
 package android.testing;
 
+import static org.junit.Assert.assertEquals;
+
 import android.content.ContentProviderClient;
 import android.content.Context;
 import android.os.Bundle;
@@ -25,8 +27,6 @@
 
 import java.util.HashMap;
 
-import static org.junit.Assert.*;
-
 /**
  * Allows calls to android.provider.Settings to be tested easier.
  *
@@ -71,7 +71,7 @@
 
     public Bundle call(String method, String arg, Bundle extras) {
         // Methods are "GET_system", "GET_global", "PUT_secure", etc.
-        final int userId = extras.getInt(Settings.CALL_METHOD_USER_KEY, 0);
+        final int userId = extras.getInt(Settings.CALL_METHOD_USER_KEY, UserHandle.myUserId());
         final String[] commands = method.split("_", 2);
         final String op = commands[0];
         final String table = commands[1];
diff --git a/tools/bit/main.cpp b/tools/bit/main.cpp
index d80c2e7..fd184f5 100644
--- a/tools/bit/main.cpp
+++ b/tools/bit/main.cpp
@@ -708,10 +708,12 @@
         }
     }
 
+
     // Figure out whether we need to sync the system and which apks to install
     string deviceTargetPath = buildOut + "/target/product/" + buildDevice;
     string systemPath = deviceTargetPath + "/system/";
     string dataPath = deviceTargetPath + "/data/";
+    string testPath = deviceTargetPath + "/testcases/";
     bool syncSystem = false;
     bool alwaysSyncSystem = false;
     vector<string> systemFiles;
@@ -734,7 +736,8 @@
                     continue;
                 }
                 // Apk in the data partition
-                if (starts_with(file, dataPath) && ends_with(file, ".apk")) {
+                if (ends_with(file, ".apk")
+                        && (starts_with(file, dataPath) || starts_with(file, testPath))) {
                     // Always install it if we didn't build it because otherwise
                     // it will never have changed.
                     installApks.push_back(InstallApk(file, !target->build));
@@ -966,8 +969,9 @@
             for (size_t j=0; j<target->module.installed.size(); j++) {
                 string filename = target->module.installed[j];
 
-                // Apk in the data partition
-                if (!starts_with(filename, dataPath) || !ends_with(filename, ".apk")) {
+                // Skip of not apk in the data partition or test
+                if (!(ends_with(filename, ".apk")
+                        && (starts_with(filename, dataPath) || starts_with(filename, testPath)))) {
                     continue;
                 }
 
diff --git a/tools/codegen/src/com/android/codegen/ClassInfo.kt b/tools/codegen/src/com/android/codegen/ClassInfo.kt
index 92da9da..bf95a2e 100644
--- a/tools/codegen/src/com/android/codegen/ClassInfo.kt
+++ b/tools/codegen/src/com/android/codegen/ClassInfo.kt
@@ -1,47 +1,15 @@
 package com.android.codegen
 
-import com.github.javaparser.ParseProblemException
-import com.github.javaparser.ParseResult
-import com.github.javaparser.ast.CompilationUnit
 import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
 
-open class ClassInfo(val sourceLines: List<String>) {
+open class ClassInfo(val classAst: ClassOrInterfaceDeclaration, val fileInfo: FileInfo) {
 
-    private val userSourceCode = (sourceLines + "}").joinToString("\n")
-    val fileAst: CompilationUnit = try {
-        JAVA_PARSER.parse(userSourceCode).throwIfFailed()
-    } catch (e: ParseProblemException) {
-        throw parseFailed(cause = e)
-    }
+    val fileAst = fileInfo.fileAst
 
-    fun <T> ParseResult<T>.throwIfFailed(): T {
-        if (problems.isNotEmpty()) {
-            throw parseFailed(
-                    desc = this@throwIfFailed.problems.joinToString("\n"),
-                    cause = this@throwIfFailed.problems.mapNotNull { it.cause.orElse(null) }.firstOrNull())
-        }
-        return result.get()
-    }
-
-    private fun parseFailed(cause: Throwable? = null, desc: String = ""): RuntimeException {
-        return RuntimeException("Failed to parse code:\n" +
-                userSourceCode
-                        .lines()
-                        .mapIndexed { lnNum, ln -> "/*$lnNum*/$ln" }
-                        .joinToString("\n") + "\n$desc",
-                cause)
-    }
-
-    val classAst = fileAst.types[0] as ClassOrInterfaceDeclaration
     val nestedClasses = classAst.members.filterIsInstance<ClassOrInterfaceDeclaration>()
 
-    val superInterfaces = (fileAst.types[0] as ClassOrInterfaceDeclaration)
-            .implementedTypes.map { it.asString() }
-
-    val superClass = run {
-        val superClasses = (fileAst.types[0] as ClassOrInterfaceDeclaration).extendedTypes
-        if (superClasses.isNonEmpty) superClasses[0] else null
-    }
+    val superInterfaces = classAst.implementedTypes.map { it.asString() }
+    val superClass = classAst.extendedTypes.getOrNull(0)
 
     val ClassName = classAst.nameAsString
     private val genericArgsAst = classAst.typeParameters
diff --git a/tools/codegen/src/com/android/codegen/ClassPrinter.kt b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
index bd72d9e..a4fd374 100644
--- a/tools/codegen/src/com/android/codegen/ClassPrinter.kt
+++ b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
@@ -11,36 +11,12 @@
  * [ClassInfo] + utilities for printing out new class code with proper indentation and imports
  */
 class ClassPrinter(
-    source: List<String>,
-    private val stringBuilder: StringBuilder,
-    var cliArgs: Array<String>
-) : ClassInfo(source) {
+        classAst: ClassOrInterfaceDeclaration,
+        fileInfo: FileInfo
+) : ClassInfo(classAst, fileInfo), Printer<ClassPrinter>, ImportsProvider {
 
     val GENERATED_MEMBER_HEADER by lazy { "@$GeneratedMember" }
 
-    // Imports
-    val NonNull by lazy { classRef("android.annotation.NonNull") }
-    val NonEmpty by lazy { classRef("android.annotation.NonEmpty") }
-    val Nullable by lazy { classRef("android.annotation.Nullable") }
-    val TextUtils by lazy { classRef("android.text.TextUtils") }
-    val LinkedHashMap by lazy { classRef("java.util.LinkedHashMap") }
-    val Collections by lazy { classRef("java.util.Collections") }
-    val Preconditions by lazy { classRef("com.android.internal.util.Preconditions") }
-    val ArrayList by lazy { classRef("java.util.ArrayList") }
-    val DataClass by lazy { classRef("com.android.internal.util.DataClass") }
-    val DataClassEnum by lazy { classRef("com.android.internal.util.DataClass.Enum") }
-    val ParcelWith by lazy { classRef("com.android.internal.util.DataClass.ParcelWith") }
-    val PluralOf by lazy { classRef("com.android.internal.util.DataClass.PluralOf") }
-    val Each by lazy { classRef("com.android.internal.util.DataClass.Each") }
-    val DataClassGenerated by lazy { classRef("com.android.internal.util.DataClass.Generated") }
-    val DataClassSuppressConstDefs by lazy { classRef("com.android.internal.util.DataClass.SuppressConstDefsGeneration") }
-    val DataClassSuppress by lazy { classRef("com.android.internal.util.DataClass.Suppress") }
-    val GeneratedMember by lazy { classRef("com.android.internal.util.DataClass.Generated.Member") }
-    val Parcelling by lazy { classRef("com.android.internal.util.Parcelling") }
-    val Parcelable by lazy { classRef("android.os.Parcelable") }
-    val Parcel by lazy { classRef("android.os.Parcel") }
-    val UnsupportedAppUsage by lazy { classRef("android.annotation.UnsupportedAppUsage") }
-
     init {
         val fieldsWithMissingNullablity = fields.filter { field ->
             !field.isPrimitive
@@ -60,49 +36,60 @@
         }
     }
 
-    /**
-     * Optionally shortens a class reference if there's a corresponding import present
-     */
-    fun classRef(fullName: String): String {
-        if (cliArgs.contains(FLAG_NO_FULL_QUALIFIERS)) {
-            return fullName.split(".").dropWhile { it[0].isLowerCase() }.joinToString(".")
-        }
+    val cliArgs get() = fileInfo.cliArgs
 
-        val pkg = fullName.substringBeforeLast(".")
-        val simpleName = fullName.substringAfterLast(".")
-        if (fileAst.imports.any { imprt ->
-                    imprt.nameAsString == fullName
-                            || (imprt.isAsterisk && imprt.nameAsString == pkg)
-                }) {
-            return simpleName
-        } else {
-            val outerClass = pkg.substringAfterLast(".", "")
-            if (outerClass.firstOrNull()?.isUpperCase() == true) {
-                return classRef(pkg) + "." + simpleName
-            }
+    fun print() {
+        currentIndent = fileInfo.sourceLines
+                .find { "class $ClassName" in it }!!
+                .takeWhile { it.isWhitespace() }
+                .plus(INDENT_SINGLE)
+
+        +fileInfo.generatedWarning
+
+        if (FeatureFlag.CONST_DEFS()) generateConstDefs()
+
+
+        if (FeatureFlag.CONSTRUCTOR()) {
+            generateConstructor("public")
+        } else if (FeatureFlag.BUILDER()
+                || FeatureFlag.COPY_CONSTRUCTOR()
+                || FeatureFlag.WITHERS()) {
+            generateConstructor("/* package-private */")
         }
-        return fullName
+        if (FeatureFlag.COPY_CONSTRUCTOR()) generateCopyConstructor()
+
+        if (FeatureFlag.GETTERS()) generateGetters()
+        if (FeatureFlag.SETTERS()) generateSetters()
+        if (FeatureFlag.TO_STRING()) generateToString()
+        if (FeatureFlag.EQUALS_HASH_CODE()) generateEqualsHashcode()
+
+        if (FeatureFlag.FOR_EACH_FIELD()) generateForEachField()
+
+        if (FeatureFlag.WITHERS()) generateWithers()
+
+        if (FeatureFlag.PARCELABLE()) generateParcelable()
+
+        if (FeatureFlag.BUILDER() && FeatureFlag.BUILD_UPON()) generateBuildUpon()
+        if (FeatureFlag.BUILDER()) generateBuilder()
+
+        if (FeatureFlag.AIDL()) fileInfo.generateAidl() //TODO guard against nested classes requesting aidl
+
+        generateMetadata(fileInfo.file)
+
+        +"""
+        //@formatter:on
+        $GENERATED_END
+        
+        """
+
+        rmEmptyLine()
     }
 
-    /** @see classRef */
-    inline fun <reified T : Any> classRef(): String {
-        return classRef(T::class.java.name)
-    }
+    override var currentIndent: String
+        get() = fileInfo.currentIndent
+        set(value) { fileInfo.currentIndent = value }
+    override val stringBuilder get() = fileInfo.stringBuilder
 
-    /** @see classRef */
-    fun memberRef(fullName: String): String {
-        val className = fullName.substringBeforeLast(".")
-        val methodName = fullName.substringAfterLast(".")
-        return if (fileAst.imports.any {
-                    it.isStatic
-                            && (it.nameAsString == fullName
-                            || (it.isAsterisk && it.nameAsString == className))
-                }) {
-            className.substringAfterLast(".") + "." + methodName
-        } else {
-            classRef(className) + "." + methodName
-        }
-    }
 
     val dataClassAnnotationFeatures = classAst.annotations
             .find { it.nameAsString == DataClass }
@@ -143,7 +130,7 @@
                     || onByDefault
             FeatureFlag.CONSTRUCTOR -> !FeatureFlag.BUILDER()
             FeatureFlag.PARCELABLE -> "Parcelable" in superInterfaces
-            FeatureFlag.AIDL -> FeatureFlag.PARCELABLE()
+            FeatureFlag.AIDL -> fileInfo.mainClass.nameAsString == ClassName && FeatureFlag.PARCELABLE()
             FeatureFlag.IMPLICIT_NONNULL -> fields.any { it.isNullable }
                     && fields.none { "@$NonNull" in it.annotations }
             else -> onByDefault
@@ -163,162 +150,7 @@
             }
         }
 
-    var currentIndent = INDENT_SINGLE
-        private set
 
-    fun pushIndent() {
-        currentIndent += INDENT_SINGLE
-    }
-
-    fun popIndent() {
-        currentIndent = currentIndent.substring(0, currentIndent.length - INDENT_SINGLE.length)
-    }
-
-    fun backspace() = stringBuilder.setLength(stringBuilder.length - 1)
-    val lastChar get() = stringBuilder[stringBuilder.length - 1]
-
-    private fun appendRaw(s: String) {
-        stringBuilder.append(s)
-    }
-
-    fun append(s: String) {
-        if (s.isBlank() && s != "\n") {
-            appendRaw(s)
-        } else {
-            appendRaw(s.lines().map { line ->
-                if (line.startsWith(" *")) line else line.trimStart()
-            }.joinToString("\n$currentIndent"))
-        }
-    }
-
-    fun appendSameLine(s: String) {
-        while (lastChar.isWhitespace() || lastChar.isNewline()) {
-            backspace()
-        }
-        appendRaw(s)
-    }
-
-    fun rmEmptyLine() {
-        while (lastChar.isWhitespaceNonNewline()) backspace()
-        if (lastChar.isNewline()) backspace()
-    }
-
-    /**
-     * Syntactic sugar for:
-     * ```
-     * +"code()";
-     * ```
-     * to append the given string plus a newline
-     */
-    operator fun String.unaryPlus() = append("$this\n")
-
-    /**
-     * Syntactic sugar for:
-     * ```
-     * !"code()";
-     * ```
-     * to append the given string without a newline
-     */
-    operator fun String.not() = append(this)
-
-    /**
-     * Syntactic sugar for:
-     * ```
-     * ... {
-     *     ...
-     * }+";"
-     * ```
-     * to append a ';' on same line after a block, and a newline afterwards
-     */
-    operator fun Unit.plus(s: String) {
-        appendSameLine(s)
-        +""
-    }
-
-    /**
-     * A multi-purpose syntactic sugar for appending the given string plus anything generated in
-     * the given [block], the latter with the appropriate deeper indent,
-     * and resetting the indent back to original at the end
-     *
-     * Usage examples:
-     *
-     * ```
-     * "if (...)" {
-     *     ...
-     * }
-     * ```
-     * to append a corresponding if block appropriate indentation
-     *
-     * ```
-     * "void foo(...)" {
-     *      ...
-     * }
-     * ```
-     * similar to the previous one, plus an extra empty line after the function body
-     *
-     * ```
-     * "void foo(" {
-     *      <args code>
-     * }
-     * ```
-     * to use proper indentation for args code and close the bracket on same line at end
-     *
-     * ```
-     * "..." {
-     *     ...
-     * }
-     * to use the correct indentation for inner code, resetting it at the end
-     */
-    inline operator fun String.invoke(block: ClassPrinter.() -> Unit) {
-        if (this == " {") {
-            appendSameLine(this)
-        } else {
-            append(this)
-        }
-        when {
-            endsWith("(") -> {
-                indentedBy(2, block)
-                appendSameLine(")")
-            }
-            endsWith("{") || endsWith(")") -> {
-                if (!endsWith("{")) appendSameLine(" {")
-                indentedBy(1, block)
-                +"}"
-                if ((endsWith(") {") || endsWith(")") || this == " {")
-                        && !startsWith("synchronized")
-                        && !startsWith("switch")
-                        && !startsWith("if ")
-                        && !contains(" else ")
-                        && !contains("new ")
-                        && !contains("return ")) {
-                    +"" // extra line after function definitions
-                }
-            }
-            else -> indentedBy(2, block)
-        }
-    }
-
-    inline fun indentedBy(level: Int, block: ClassPrinter.() -> Unit) {
-        append("\n")
-        level times {
-            append(INDENT_SINGLE)
-            pushIndent()
-        }
-        block()
-        level times { popIndent() }
-        rmEmptyLine()
-        +""
-    }
-
-    inline fun Iterable<FieldInfo>.forEachTrimmingTrailingComma(b: FieldInfo.() -> Unit) {
-        forEachApply {
-            b()
-            if (isLast) {
-                while (lastChar == ' ' || lastChar == '\n') backspace()
-                if (lastChar == ',') backspace()
-            }
-        }
-    }
 
     inline operator fun <R> invoke(f: ClassPrinter.() -> R): R = run(f)
 
@@ -381,10 +213,10 @@
             BuilderClass = (builderFactoryOverride.type as ClassOrInterfaceType).nameAsString
             BuilderType = builderFactoryOverride.type.asString()
         } else {
-            val builderExtension = (fileAst.types
-                    + classAst.childNodes.filterIsInstance(TypeDeclaration::class.java)).find {
-                it.nameAsString == CANONICAL_BUILDER_CLASS
-            }
+            val builderExtension = classAst
+                    .childNodes
+                    .filterIsInstance(TypeDeclaration::class.java)
+                    .find { it.nameAsString == CANONICAL_BUILDER_CLASS }
             if (builderExtension != null) {
                 BuilderClass = BASE_BUILDER_CLASS
                 val tp = (builderExtension as ClassOrInterfaceDeclaration).typeParameters
diff --git a/tools/codegen/src/com/android/codegen/FieldInfo.kt b/tools/codegen/src/com/android/codegen/FieldInfo.kt
index 1a7fd6e..ed35a1d 100644
--- a/tools/codegen/src/com/android/codegen/FieldInfo.kt
+++ b/tools/codegen/src/com/android/codegen/FieldInfo.kt
@@ -1,5 +1,6 @@
 package com.android.codegen
 
+import com.github.javaparser.JavaParser
 import com.github.javaparser.ast.body.FieldDeclaration
 import com.github.javaparser.ast.expr.ClassExpr
 import com.github.javaparser.ast.expr.Name
@@ -111,11 +112,12 @@
     val annotations by lazy {
         if (FieldClass in BUILTIN_SPECIAL_PARCELLINGS) {
             classPrinter {
-                fieldAst.addAnnotation(SingleMemberAnnotationExpr(
-                        Name(ParcelWith),
-                        ClassExpr(JAVA_PARSER
-                                .parseClassOrInterfaceType("$Parcelling.BuiltIn.For$FieldClass")
-                                .throwIfFailed())))
+                fileInfo.apply {
+                    fieldAst.addAnnotation(SingleMemberAnnotationExpr(
+                            Name(ParcelWith),
+                            ClassExpr(parseJava(JavaParser::parseClassOrInterfaceType,
+                                    "$Parcelling.BuiltIn.For$FieldClass"))))
+                }
             }
         }
         fieldAst.annotations.map { it.removeComment().toString() }
diff --git a/tools/codegen/src/com/android/codegen/FileInfo.kt b/tools/codegen/src/com/android/codegen/FileInfo.kt
new file mode 100644
index 0000000..9094726
--- /dev/null
+++ b/tools/codegen/src/com/android/codegen/FileInfo.kt
@@ -0,0 +1,289 @@
+/*
+ * 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.codegen
+
+import com.github.javaparser.JavaParser
+import com.github.javaparser.ast.CompilationUnit
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
+import com.github.javaparser.ast.body.TypeDeclaration
+import java.io.File
+
+/**
+ * File-level parsing & printing logic
+ *
+ * @see [main] entrypoint
+ */
+class FileInfo(
+        val sourceLines: List<String>,
+        val cliArgs: Array<String>,
+        val file: File)
+    : Printer<FileInfo>, ImportsProvider {
+
+    override val fileAst: CompilationUnit
+            = parseJava(JavaParser::parse, sourceLines.joinToString("\n"))
+
+    override val stringBuilder = StringBuilder()
+    override var currentIndent = INDENT_SINGLE
+
+
+    val generatedWarning = run {
+        val fileEscaped = file.absolutePath.replace(
+                System.getenv("ANDROID_BUILD_TOP"), "\$ANDROID_BUILD_TOP")
+
+        """
+
+
+        // $GENERATED_WARNING_PREFIX v$CODEGEN_VERSION.
+        //
+        // DO NOT MODIFY!
+        // CHECKSTYLE:OFF Generated code
+        //
+        // To regenerate run:
+        // $ $THIS_SCRIPT_LOCATION$CODEGEN_NAME ${cliArgs.dropLast(1).joinToString("") { "$it " }}$fileEscaped
+        //
+        // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+        //   Settings > Editor > Code Style > Formatter Control
+        //@formatter:off
+
+        """
+    }
+    private val generatedWarningNumPrecedingEmptyLines
+            = generatedWarning.lines().takeWhile { it.isBlank() }.size
+
+    val classes = fileAst.types
+            .filterIsInstance<ClassOrInterfaceDeclaration>()
+            .flatMap { it.plusNested() }
+            .filterNot { it.isInterface }
+
+    val mainClass = classes.find { it.nameAsString == file.nameWithoutExtension }!!
+
+    // Parse stage 1
+    val classBounds: List<ClassBounds> = classes.map { ast ->
+        ClassBounds(ast, fileInfo = this)
+    }.apply {
+        forEachApply {
+            if (ast.isNestedType) {
+                val parent = find {
+                    it.name == (ast.parentNode.get()!! as TypeDeclaration<*>).nameAsString
+                }!!
+                parent.nested.add(this)
+                nestedIn = parent
+            }
+        }
+    }
+
+    // Parse Stage 2
+    var codeChunks = buildList<CodeChunk> {
+        val mainClassBounds = classBounds.find { it.nestedIn == null }!!
+        add(CodeChunk.FileHeader(
+                mainClassBounds.fileInfo.sourceLines.subList(0, mainClassBounds.range.start)))
+        add(CodeChunk.DataClass.parse(mainClassBounds))
+    }
+
+    // Output stage
+    fun main() {
+        codeChunks.forEach { print(it) }
+    }
+
+    fun print(chunk: CodeChunk) {
+        when(chunk) {
+            is CodeChunk.GeneratedCode -> {
+                // Re-parse class code, discarding generated code and nested dataclasses
+                val ast = chunk.owner.chunks
+                        .filter {
+                            it.javaClass == CodeChunk.Code::class.java
+                                    || it.javaClass == CodeChunk.ClosingBrace::class.java
+                        }
+                        .flatMap { (it as CodeChunk.Code).lines }
+                        .joinToString("\n")
+                        .let {
+                            parseJava(JavaParser::parseTypeDeclaration, it)
+                                    as ClassOrInterfaceDeclaration
+                        }
+
+                // Write new generated code
+                ClassPrinter(ast, fileInfo = this).print()
+            }
+            is CodeChunk.ClosingBrace -> {
+                // Special case - print closing brace with -1 indent
+                rmEmptyLine()
+                popIndent()
+                +"\n}"
+            }
+            // Print general code as-is
+            is CodeChunk.Code -> chunk.lines.forEach { stringBuilder.appendln(it) }
+            // Recursively render data classes
+            is CodeChunk.DataClass -> chunk.chunks.forEach { print(it) }
+        }
+    }
+
+    /**
+     * Output of stage 1 of parsing a file:
+     * Recursively nested ranges of code line numbers containing nested classes
+     */
+    data class ClassBounds(
+            val ast: ClassOrInterfaceDeclaration,
+            val fileInfo: FileInfo,
+            val name: String = ast.nameAsString,
+            val range: ClosedRange<Int> = ast.range.get()!!.let { rng -> rng.begin.line-1..rng.end.line-1 },
+            val nested: MutableList<ClassBounds> = mutableListOf(),
+            var nestedIn: ClassBounds? = null) {
+
+        val nestedDataClasses: List<ClassBounds> by lazy {
+            nested.filter { it.isDataclass }.sortedBy { it.range.start }
+        }
+        val isDataclass = ast.annotations.any { it.nameAsString.endsWith("DataClass") }
+
+        val baseIndentLength = fileInfo.sourceLines.find { "class $name" in it }!!.takeWhile { it == ' ' }.length
+        val baseIndent = buildString { repeat(baseIndentLength) { append(' ') } }
+
+        val sourceNoPrefix = fileInfo.sourceLines.drop(range.start)
+        val generatedCodeRange = sourceNoPrefix
+                .indexOfFirst { it.startsWith("$baseIndent$INDENT_SINGLE// $GENERATED_WARNING_PREFIX") }
+                .let { start ->
+                    if (start < 0) {
+                        null
+                    } else {
+                        var endInclusive = sourceNoPrefix.indexOfFirst {
+                            it.startsWith("$baseIndent$INDENT_SINGLE$GENERATED_END")
+                        }
+                        if (endInclusive == -1) {
+                            // Legacy generated code doesn't have end markers
+                            endInclusive = sourceNoPrefix.size - 2
+                        }
+                        IntRange(
+                                range.start + start - fileInfo.generatedWarningNumPrecedingEmptyLines,
+                                range.start + endInclusive)
+                    }
+                }
+
+        /** Debug info */
+        override fun toString(): String {
+            return buildString {
+                appendln("class $name $range")
+                nested.forEach {
+                    appendln(it)
+                }
+                appendln("end $name")
+            }
+        }
+    }
+
+    /**
+     * Output of stage 2 of parsing a file
+     */
+    sealed class CodeChunk {
+        /** General code */
+        open class Code(val lines: List<String>): CodeChunk() {}
+
+        /** Copyright + package + imports + main javadoc */
+        class FileHeader(lines: List<String>): Code(lines)
+
+        /** Code to be discarded and refreshed */
+        open class GeneratedCode(lines: List<String>): Code(lines) {
+            lateinit var owner: DataClass
+
+            class Placeholder: GeneratedCode(emptyList())
+        }
+
+        object ClosingBrace: Code(listOf("}"))
+
+        data class DataClass(
+                val ast: ClassOrInterfaceDeclaration,
+                val chunks: List<CodeChunk>,
+                val generatedCode: GeneratedCode?): CodeChunk() {
+
+            companion object {
+                fun parse(classBounds: ClassBounds): DataClass {
+                    val initial = Code(lines = classBounds.fileInfo.sourceLines.subList(
+                            fromIndex = classBounds.range.start,
+                            toIndex = findLowerBound(
+                                    thisClass = classBounds,
+                                    nextNestedClass = classBounds.nestedDataClasses.getOrNull(0))))
+
+                    val chunks = mutableListOf<CodeChunk>(initial)
+
+                    classBounds.nestedDataClasses.forEachSequentialPair {
+                            nestedDataClass, nextNestedDataClass ->
+                        chunks += DataClass.parse(nestedDataClass)
+                        chunks += Code(lines = classBounds.fileInfo.sourceLines.subList(
+                                fromIndex = nestedDataClass.range.endInclusive + 1,
+                                toIndex = findLowerBound(
+                                        thisClass = classBounds,
+                                        nextNestedClass = nextNestedDataClass)))
+                    }
+
+                    var generatedCode = classBounds.generatedCodeRange?.let { rng ->
+                        GeneratedCode(classBounds.fileInfo.sourceLines.subList(
+                                rng.start, rng.endInclusive+1))
+                    }
+                    if (generatedCode != null) {
+                        chunks += generatedCode
+                        chunks += ClosingBrace
+                    } else if (classBounds.isDataclass) {
+
+                        // Insert placeholder for generated code to be inserted for the 1st time
+                        chunks.last = (chunks.last as Code)
+                                .lines
+                                .dropLastWhile { it.isBlank() }
+                                .run {
+                                    if (last().dropWhile { it.isWhitespace() }.startsWith("}")) {
+                                        dropLast(1)
+                                    } else {
+                                        this
+                                    }
+                                }.let { Code(it) }
+                        generatedCode = GeneratedCode.Placeholder()
+                        chunks += generatedCode
+                        chunks += ClosingBrace
+                    } else {
+                        // Outer class may be not a @DataClass but contain ones
+                        // so just skip generated code for them
+                    }
+
+                    return DataClass(classBounds.ast, chunks, generatedCode).also {
+                        generatedCode?.owner = it
+                    }
+                }
+
+                private fun findLowerBound(thisClass: ClassBounds, nextNestedClass: ClassBounds?): Int {
+                    return nextNestedClass?.range?.start
+                            ?: thisClass.generatedCodeRange?.start
+                            ?: thisClass.range.endInclusive + 1
+                }
+            }
+        }
+
+        /** Debug info */
+        fun summary(): String = when(this) {
+            is Code -> "${javaClass.simpleName}(${lines.size} lines): ${lines.getOrNull(0)?.take(70) ?: ""}..."
+            is DataClass -> "DataClass ${ast.nameAsString}:\n" +
+                    chunks.joinToString("\n") { it.summary() } +
+                    "\n//end ${ast.nameAsString}"
+        }
+    }
+
+    private fun ClassOrInterfaceDeclaration.plusNested(): List<ClassOrInterfaceDeclaration> {
+        return mutableListOf<ClassOrInterfaceDeclaration>().apply {
+            add(this@plusNested)
+            childNodes.filterIsInstance<ClassOrInterfaceDeclaration>()
+                    .flatMap { it.plusNested() }
+                    .let { addAll(it) }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt
index 431f378..c25d0c7 100644
--- a/tools/codegen/src/com/android/codegen/Generators.kt
+++ b/tools/codegen/src/com/android/codegen/Generators.kt
@@ -119,14 +119,14 @@
     }
 }
 
-fun ClassPrinter.generateAidl(javaFile: File) {
-    val aidl = File(javaFile.path.substringBeforeLast(".java") + ".aidl")
+fun FileInfo.generateAidl() {
+    val aidl = File(file.path.substringBeforeLast(".java") + ".aidl")
     if (aidl.exists()) return
     aidl.writeText(buildString {
         sourceLines.dropLastWhile { !it.startsWith("package ") }.forEach {
             appendln(it)
         }
-        append("\nparcelable $ClassName;\n")
+        append("\nparcelable ${mainClass.nameAsString};\n")
     })
 }
 
@@ -212,13 +212,15 @@
         "Object"
     }
 
+    val maybeFinal = if_(classAst.isFinal, "final ")
+
     +"/**"
     +" * A builder for {@link $ClassName}"
     if (FeatureFlag.BUILDER.hidden) +" * @hide"
     +" */"
     +"@SuppressWarnings(\"WeakerAccess\")"
     +GENERATED_MEMBER_HEADER
-    !"public static class $BuilderClass$genericArgs"
+    !"public static ${maybeFinal}class $BuilderClass$genericArgs"
     if (BuilderSupertype != "Object") {
         appendSameLine(" extends $BuilderSupertype")
     }
@@ -359,7 +361,7 @@
 
 private fun ClassPrinter.generateBuilderBuild() {
     +"/** Builds the instance. This builder should not be touched after calling this! */"
-    "public $ClassType build()" {
+    "public @$NonNull $ClassType build()" {
         +"checkNotUsed();"
         +"mBuilderFieldsSet |= ${bitAtExpr(fields.size)}; // Mark builder used"
         +""
diff --git a/tools/codegen/src/com/android/codegen/ImportsProvider.kt b/tools/codegen/src/com/android/codegen/ImportsProvider.kt
new file mode 100644
index 0000000..ba0a031
--- /dev/null
+++ b/tools/codegen/src/com/android/codegen/ImportsProvider.kt
@@ -0,0 +1,91 @@
+/*
+ * 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.codegen
+
+import com.github.javaparser.ast.CompilationUnit
+
+/**
+ * Mixin for optionally shortening references based on existing imports
+ */
+interface ImportsProvider {
+
+    abstract val fileAst: CompilationUnit
+
+    val NonNull: String get() { return classRef("android.annotation.NonNull") }
+    val NonEmpty: String get() { return classRef("android.annotation.NonEmpty") }
+    val Nullable: String get() { return classRef("android.annotation.Nullable") }
+    val TextUtils: String get() { return classRef("android.text.TextUtils") }
+    val LinkedHashMap: String get() { return classRef("java.util.LinkedHashMap") }
+    val Collections: String get() { return classRef("java.util.Collections") }
+    val Preconditions: String get() { return classRef("com.android.internal.util.Preconditions") }
+    val ArrayList: String get() { return classRef("java.util.ArrayList") }
+    val DataClass: String get() { return classRef("com.android.internal.util.DataClass") }
+    val DataClassEnum: String get() { return classRef("com.android.internal.util.DataClass.Enum") }
+    val ParcelWith: String get() { return classRef("com.android.internal.util.DataClass.ParcelWith") }
+    val PluralOf: String get() { return classRef("com.android.internal.util.DataClass.PluralOf") }
+    val Each: String get() { return classRef("com.android.internal.util.DataClass.Each") }
+    val DataClassGenerated: String get() { return classRef("com.android.internal.util.DataClass.Generated") }
+    val DataClassSuppressConstDefs: String get() { return classRef("com.android.internal.util.DataClass.SuppressConstDefsGeneration") }
+    val DataClassSuppress: String get() { return classRef("com.android.internal.util.DataClass.Suppress") }
+    val GeneratedMember: String get() { return classRef("com.android.internal.util.DataClass.Generated.Member") }
+    val Parcelling: String get() { return classRef("com.android.internal.util.Parcelling") }
+    val Parcelable: String get() { return classRef("android.os.Parcelable") }
+    val Parcel: String get() { return classRef("android.os.Parcel") }
+    val UnsupportedAppUsage: String get() { return classRef("android.annotation.UnsupportedAppUsage") }
+
+    /**
+     * Optionally shortens a class reference if there's a corresponding import present
+     */
+    fun classRef(fullName: String): String {
+
+        val pkg = fullName.substringBeforeLast(".")
+        val simpleName = fullName.substringAfterLast(".")
+        if (fileAst.imports.any { imprt ->
+                    imprt.nameAsString == fullName
+                            || (imprt.isAsterisk && imprt.nameAsString == pkg)
+                }) {
+            return simpleName
+        } else {
+            val outerClass = pkg.substringAfterLast(".", "")
+            if (outerClass.firstOrNull()?.isUpperCase() == true) {
+                return classRef(pkg) + "." + simpleName
+            }
+        }
+        return fullName
+    }
+
+    /** @see classRef */
+    fun memberRef(fullName: String): String {
+        val className = fullName.substringBeforeLast(".")
+        val methodName = fullName.substringAfterLast(".")
+        return if (fileAst.imports.any {
+                    it.isStatic
+                            && (it.nameAsString == fullName
+                            || (it.isAsterisk && it.nameAsString == className))
+                }) {
+            className.substringAfterLast(".") + "." + methodName
+        } else {
+            classRef(className) + "." + methodName
+        }
+    }
+}
+
+/** @see classRef */
+inline fun <reified T : Any> ImportsProvider.classRef(): String {
+    return classRef(T::class.java.name)
+}
\ No newline at end of file
diff --git a/tools/codegen/src/com/android/codegen/Main.kt b/tools/codegen/src/com/android/codegen/Main.kt
index ce83d3d..4b508d0 100755
--- a/tools/codegen/src/com/android/codegen/Main.kt
+++ b/tools/codegen/src/com/android/codegen/Main.kt
@@ -6,6 +6,7 @@
 
 const val THIS_SCRIPT_LOCATION = ""
 const val GENERATED_WARNING_PREFIX = "Code below generated by $CODEGEN_NAME"
+const val GENERATED_END = "// End of generated code"
 const val INDENT_SINGLE = "    "
 
 val PRIMITIVE_TYPES = listOf("byte", "short", "int", "long", "char", "float", "double", "boolean")
@@ -115,81 +116,15 @@
         System.exit(0)
     }
     val file = File(args.last()).absoluteFile
-    val sourceLinesNoClosingBrace = file.readLines().dropLastWhile {
+    val sourceLisnesOriginal = file.readLines()
+    val sourceLinesNoClosingBrace = sourceLisnesOriginal.dropLastWhile {
         it.startsWith("}") || it.all(Char::isWhitespace)
     }
     val cliArgs = handleUpdateFlag(args, sourceLinesNoClosingBrace)
-    val sourceLinesAsIs = discardGeneratedCode(sourceLinesNoClosingBrace)
-    val sourceLines = sourceLinesAsIs
-            .filterNot { it.trim().startsWith("//") }
-            .map { it.trimEnd().dropWhile { it == '\n' } }
 
-    val stringBuilder = StringBuilder(sourceLinesAsIs.joinToString("\n"))
-    ClassPrinter(sourceLines, stringBuilder, cliArgs).run {
-
-        val cliExecutable = "$THIS_SCRIPT_LOCATION$CODEGEN_NAME"
-        val fileEscaped = file.absolutePath.replace(
-                System.getenv("ANDROID_BUILD_TOP"), "\$ANDROID_BUILD_TOP")
-
-
-        +"""
-
-
-
-        // $GENERATED_WARNING_PREFIX v$CODEGEN_VERSION.
-        //
-        // DO NOT MODIFY!
-        // CHECKSTYLE:OFF Generated code
-        //
-        // To regenerate run:
-        // $ $cliExecutable ${cliArgs.dropLast(1).joinToString("") { "$it " }}$fileEscaped
-        //
-        // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
-        //   Settings > Editor > Code Style > Formatter Control
-        //@formatter:off
-
-        """
-
-        if (FeatureFlag.CONST_DEFS()) generateConstDefs()
-
-
-        if (FeatureFlag.CONSTRUCTOR()) {
-            generateConstructor("public")
-        } else if (FeatureFlag.BUILDER()
-                || FeatureFlag.COPY_CONSTRUCTOR()
-                || FeatureFlag.WITHERS()) {
-            generateConstructor("/* package-private */")
-        }
-        if (FeatureFlag.COPY_CONSTRUCTOR()) generateCopyConstructor()
-
-        if (FeatureFlag.GETTERS()) generateGetters()
-        if (FeatureFlag.SETTERS()) generateSetters()
-        if (FeatureFlag.TO_STRING()) generateToString()
-        if (FeatureFlag.EQUALS_HASH_CODE()) generateEqualsHashcode()
-
-        if (FeatureFlag.FOR_EACH_FIELD()) generateForEachField()
-
-        if (FeatureFlag.WITHERS()) generateWithers()
-
-        if (FeatureFlag.PARCELABLE()) generateParcelable()
-
-        if (FeatureFlag.BUILDER() && FeatureFlag.BUILD_UPON()) generateBuildUpon()
-        if (FeatureFlag.BUILDER()) generateBuilder()
-
-        if (FeatureFlag.AIDL()) generateAidl(file)
-
-        generateMetadata(file)
-
-        rmEmptyLine()
-    }
-    stringBuilder.append("\n}\n")
-    file.writeText(stringBuilder.toString().mapLines { trimEnd() })
-}
-
-internal fun discardGeneratedCode(sourceLinesNoClosingBrace: List<String>): List<String> {
-    return sourceLinesNoClosingBrace
-            .takeWhile { GENERATED_WARNING_PREFIX !in it }
-            .dropLastWhile(String::isBlank)
+    val fileInfo = FileInfo(sourceLisnesOriginal, cliArgs, file)
+    fileInfo.main()
+    file.writeText(fileInfo.stringBuilder.toString().mapLines { trimEnd() })
 }
 
 private fun handleUpdateFlag(cliArgs: Array<String>, sourceLines: List<String>): Array<String> {
diff --git a/tools/codegen/src/com/android/codegen/Printer.kt b/tools/codegen/src/com/android/codegen/Printer.kt
new file mode 100644
index 0000000..b30e3f6
--- /dev/null
+++ b/tools/codegen/src/com/android/codegen/Printer.kt
@@ -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.codegen
+
+/**
+ * Mixin for syntactic sugar around indent-aware printing into [stringBuilder]
+ */
+interface Printer<SELF: Printer<SELF>> {
+
+    val stringBuilder: StringBuilder
+
+    var currentIndent: String
+
+    fun pushIndent() {
+        currentIndent += INDENT_SINGLE
+    }
+
+    fun popIndent() {
+        currentIndent = if (currentIndent.length >= INDENT_SINGLE.length) {
+            currentIndent.substring(0, currentIndent.length - INDENT_SINGLE.length)
+        } else {
+            ""
+        }
+    }
+
+    fun backspace() = stringBuilder.setLength(stringBuilder.length - 1)
+    val lastChar get() = stringBuilder[stringBuilder.length - 1]
+
+    private fun appendRaw(s: String) {
+        stringBuilder.append(s)
+    }
+
+    fun append(s: String) {
+        if (s.isBlank() && s != "\n") {
+            appendRaw(s)
+        } else {
+            appendRaw(s.lines().map { line ->
+                if (line.startsWith(" *")) line else line.trimStart()
+            }.joinToString("\n$currentIndent"))
+        }
+    }
+
+    fun appendSameLine(s: String) {
+        while (lastChar.isWhitespace() || lastChar.isNewline()) {
+            backspace()
+        }
+        appendRaw(s)
+    }
+
+    fun rmEmptyLine() {
+        while (lastChar.isWhitespaceNonNewline()) backspace()
+        if (lastChar.isNewline()) backspace()
+    }
+
+    /**
+     * Syntactic sugar for:
+     * ```
+     * +"code()";
+     * ```
+     * to append the given string plus a newline
+     */
+    operator fun String.unaryPlus() = append("$this\n")
+
+    /**
+     * Syntactic sugar for:
+     * ```
+     * !"code()";
+     * ```
+     * to append the given string without a newline
+     */
+    operator fun String.not() = append(this)
+
+    /**
+     * Syntactic sugar for:
+     * ```
+     * ... {
+     *     ...
+     * }+";"
+     * ```
+     * to append a ';' on same line after a block, and a newline afterwards
+     */
+    operator fun Unit.plus(s: String) {
+        appendSameLine(s)
+        +""
+    }
+
+    /**
+     * A multi-purpose syntactic sugar for appending the given string plus anything generated in
+     * the given [block], the latter with the appropriate deeper indent,
+     * and resetting the indent back to original at the end
+     *
+     * Usage examples:
+     *
+     * ```
+     * "if (...)" {
+     *     ...
+     * }
+     * ```
+     * to append a corresponding if block appropriate indentation
+     *
+     * ```
+     * "void foo(...)" {
+     *      ...
+     * }
+     * ```
+     * similar to the previous one, plus an extra empty line after the function body
+     *
+     * ```
+     * "void foo(" {
+     *      <args code>
+     * }
+     * ```
+     * to use proper indentation for args code and close the bracket on same line at end
+     *
+     * ```
+     * "..." {
+     *     ...
+     * }
+     * to use the correct indentation for inner code, resetting it at the end
+     */
+    operator fun String.invoke(block: SELF.() -> Unit) {
+        if (this == " {") {
+            appendSameLine(this)
+        } else {
+            append(this)
+        }
+        when {
+            endsWith("(") -> {
+                indentedBy(2, block)
+                appendSameLine(")")
+            }
+            endsWith("{") || endsWith(")") -> {
+                if (!endsWith("{")) appendSameLine(" {")
+                indentedBy(1, block)
+                +"}"
+                if ((endsWith(") {") || endsWith(")") || this == " {")
+                        && !startsWith("synchronized")
+                        && !startsWith("switch")
+                        && !startsWith("if ")
+                        && !contains(" else ")
+                        && !contains("new ")
+                        && !contains("return ")) {
+                    +"" // extra line after function definitions
+                }
+            }
+            else -> indentedBy(2, block)
+        }
+    }
+
+    fun indentedBy(level: Int, block: SELF.() -> Unit) {
+        append("\n")
+        level times {
+            append(INDENT_SINGLE)
+            pushIndent()
+        }
+        (this as SELF).block()
+        level times { popIndent() }
+        rmEmptyLine()
+        +""
+    }
+
+    fun Iterable<FieldInfo>.forEachTrimmingTrailingComma(b: FieldInfo.() -> Unit) {
+        forEachApply {
+            b()
+            if (isLast) {
+                while (lastChar == ' ' || lastChar == '\n') backspace()
+                if (lastChar == ',') backspace()
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt
index 3eb9e7b..339057f 100644
--- a/tools/codegen/src/com/android/codegen/SharedConstants.kt
+++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt
@@ -1,7 +1,7 @@
 package com.android.codegen
 
 const val CODEGEN_NAME = "codegen"
-const val CODEGEN_VERSION = "1.0.9"
+const val CODEGEN_VERSION = "1.0.12"
 
 const val CANONICAL_BUILDER_CLASS = "Builder"
 const val BASE_BUILDER_CLASS = "BaseBuilder"
diff --git a/tools/codegen/src/com/android/codegen/Utils.kt b/tools/codegen/src/com/android/codegen/Utils.kt
index e703397..c19ae3b 100644
--- a/tools/codegen/src/com/android/codegen/Utils.kt
+++ b/tools/codegen/src/com/android/codegen/Utils.kt
@@ -1,5 +1,11 @@
 package com.android.codegen
 
+import com.github.javaparser.JavaParser
+import com.github.javaparser.ParseProblemException
+import com.github.javaparser.ParseResult
+import com.github.javaparser.ast.Node
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
+import com.github.javaparser.ast.body.TypeDeclaration
 import com.github.javaparser.ast.expr.*
 import com.github.javaparser.ast.nodeTypes.NodeWithModifiers
 import java.time.Instant
@@ -92,3 +98,49 @@
     is NormalAnnotationExpr -> pairs.map { it.name.asString() to it.value }.toMap()
     else -> throw IllegalArgumentException("Unknown annotation expression: $this")
 }
+
+val TypeDeclaration<*>.nestedTypes get() = childNodes.filterIsInstance<TypeDeclaration<*>>()
+val TypeDeclaration<*>.nestedDataClasses get()
+        = nestedTypes.filterIsInstance<ClassOrInterfaceDeclaration>()
+            .filter { it.annotations.any { it.nameAsString.endsWith("DataClass") } }
+val TypeDeclaration<*>.startLine get() = range.get()!!.begin.line
+
+inline fun <T> List<T>.forEachSequentialPair(action: (T, T?) -> Unit) {
+    forEachIndexed { index, t ->
+        action(t, getOrNull(index + 1))
+    }
+}
+
+fun <T: Node> parseJava(fn: JavaParser.(String) -> ParseResult<T>, source: String): T = try {
+    val parse = JAVA_PARSER.fn(source)
+    if (parse.problems.isNotEmpty()) {
+        throw parseFailed(
+                source,
+                desc = parse.problems.joinToString("\n"),
+                cause = parse.problems.mapNotNull { it.cause.orElse(null) }.firstOrNull())
+    }
+    parse.result.get()
+} catch (e: ParseProblemException) {
+    throw parseFailed(source, cause = e)
+}
+
+private fun parseFailed(source: String, cause: Throwable? = null, desc: String = ""): RuntimeException {
+    return RuntimeException("Failed to parse code:\n" +
+            source
+                    .lines()
+                    .mapIndexed { lnNum, ln -> "/*$lnNum*/$ln" }
+                    .joinToString("\n") + "\n$desc",
+            cause)
+}
+
+var <T> MutableList<T>.last
+    get() = last()
+    set(value) {
+        if (isEmpty()) {
+            add(value)
+        } else {
+            this[size - 1] = value
+        }
+    }
+
+inline fun <T> buildList(init: MutableList<T>.() -> Unit) = mutableListOf<T>().apply(init)
\ No newline at end of file
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index 91f875e..ded4b91 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -436,7 +436,9 @@
                 printf(" NULL),\n");
                 break;
             case SECTION_LOG:
-                printf("    new LogSection(%d, %s),\n", field->number(), s.args().c_str());
+                printf("    new LogSection(%d, ", field->number());
+                splitAndPrint(s.args());
+                printf(" NULL),\n");
                 break;
             case SECTION_GZIP:
                 printf("    new GZipSection(%d,", field->number());
diff --git a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
index 7fe21c7..51faa49 100644
--- a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
+++ b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
@@ -208,7 +208,16 @@
         val refreshCmd = if (file != null) {
             "$CODEGEN_NAME $file"
         } else {
-            "find \$ANDROID_BUILD_TOP -path */${clazz.replace('.', '/')}.java -exec $CODEGEN_NAME {} \\;"
+            var gotTopLevelCalssName = false
+            val filePath = clazz.split(".")
+                    .takeWhile { word ->
+                        if (!gotTopLevelCalssName && word[0].isUpperCase()) {
+                            gotTopLevelCalssName = true
+                            return@takeWhile true
+                        }
+                        !gotTopLevelCalssName
+                    }.joinToString("/")
+            "find \$ANDROID_BUILD_TOP -path */$filePath.java -exec $CODEGEN_NAME {} \\;"
         }
     }
 
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
index 629f720..99a26dc 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
@@ -24,6 +24,7 @@
 import java.io.File
 import java.io.FileInputStream
 import java.io.FileOutputStream
+import java.io.OutputStream
 import java.util.concurrent.ExecutorService
 import java.util.concurrent.Executors
 import java.util.jar.JarOutputStream
@@ -42,9 +43,10 @@
     }
 
     private fun processClasses(command: CommandOptions) {
-        val groups = ProtoLogGroupReader()
-                .loadFromJar(command.protoLogGroupsJarArg, command.protoLogGroupsClassNameArg)
-        val out = FileOutputStream(command.outputSourceJarArg)
+        val groups = injector.readLogGroups(
+                command.protoLogGroupsJarArg,
+                command.protoLogGroupsClassNameArg)
+        val out = injector.fileOutputStream(command.outputSourceJarArg)
         val outJar = JarOutputStream(out)
         val processor = ProtoLogCallProcessor(command.protoLogClassNameArg,
                 command.protoLogGroupsClassNameArg, groups)
@@ -56,18 +58,18 @@
                 val transformer = SourceTransformer(command.protoLogImplClassNameArg,
                         command.protoLogCacheClassNameArg, processor)
                 val file = File(path)
-                val text = file.readText()
+                val text = injector.readText(file)
                 val outSrc = try {
                     val code = tryParse(text, path)
                     if (containsProtoLogText(text, command.protoLogClassNameArg)) {
-                        transformer.processClass(text, path, code)
+                        transformer.processClass(text, path, packagePath(file, code), code)
                     } else {
                         text
                     }
                 } catch (ex: ParsingException) {
                     // If we cannot parse this file, skip it (and log why). Compilation will fail
                     // in a subsequent build step.
-                    println("\n${ex.message}\n")
+                    injector.reportParseError(ex)
                     text
                 }
                 path to outSrc
@@ -142,8 +144,9 @@
     }
 
     private fun viewerConf(command: CommandOptions) {
-        val groups = ProtoLogGroupReader()
-                .loadFromJar(command.protoLogGroupsJarArg, command.protoLogGroupsClassNameArg)
+        val groups = injector.readLogGroups(
+                command.protoLogGroupsJarArg,
+                command.protoLogGroupsClassNameArg)
         val processor = ProtoLogCallProcessor(command.protoLogClassNameArg,
                 command.protoLogGroupsClassNameArg, groups)
         val builder = ViewerConfigBuilder(processor)
@@ -153,18 +156,15 @@
         command.javaSourceArgs.map { path ->
             executor.submitCallable {
                 val file = File(path)
-                val text = file.readText()
+                val text = injector.readText(file)
                 if (containsProtoLogText(text, command.protoLogClassNameArg)) {
                     try {
                         val code = tryParse(text, path)
-                        val pack = if (code.packageDeclaration.isPresent) code.packageDeclaration
-                                .get().nameAsString else ""
-                        val newPath = pack.replace('.', '/') + '/' + file.name
-                        builder.findLogCalls(code, newPath)
+                        builder.findLogCalls(code, path, packagePath(file, code))
                     } catch (ex: ParsingException) {
                         // If we cannot parse this file, skip it (and log why). Compilation will fail
                         // in a subsequent build step.
-                        println("\n${ex.message}\n")
+                        injector.reportParseError(ex)
                         null
                     }
                 } else {
@@ -177,11 +177,18 @@
 
         executor.shutdown()
 
-        val out = FileOutputStream(command.viewerConfigJsonArg)
+        val out = injector.fileOutputStream(command.viewerConfigJsonArg)
         out.write(builder.build().toByteArray())
         out.close()
     }
 
+    private fun packagePath(file: File, code: CompilationUnit): String {
+        val pack = if (code.packageDeclaration.isPresent) code.packageDeclaration
+                .get().nameAsString else ""
+        val packagePath = pack.replace('.', '/') + '/' + file.name
+        return packagePath
+    }
+
     private fun read(command: CommandOptions) {
         LogParser(ViewerConfigParser())
                 .parse(FileInputStream(command.logProtofileArg),
@@ -190,18 +197,9 @@
 
     @JvmStatic
     fun main(args: Array<String>) {
-        StaticJavaParser.setConfiguration(ParserConfiguration().apply {
-            setLanguageLevel(ParserConfiguration.LanguageLevel.RAW)
-            setAttributeComments(false)
-        })
-
         try {
             val command = CommandOptions(args)
-            when (command.command) {
-                CommandOptions.TRANSFORM_CALLS_CMD -> processClasses(command)
-                CommandOptions.GENERATE_CONFIG_CMD -> viewerConf(command)
-                CommandOptions.READ_LOG_CMD -> read(command)
-            }
+            invoke(command)
         } catch (ex: InvalidCommandException) {
             println("\n${ex.message}\n")
             showHelpAndExit()
@@ -210,6 +208,36 @@
             exitProcess(1)
         }
     }
+
+    fun invoke(command: CommandOptions) {
+        StaticJavaParser.setConfiguration(ParserConfiguration().apply {
+            setLanguageLevel(ParserConfiguration.LanguageLevel.RAW)
+            setAttributeComments(false)
+        })
+
+        when (command.command) {
+            CommandOptions.TRANSFORM_CALLS_CMD -> processClasses(command)
+            CommandOptions.GENERATE_CONFIG_CMD -> viewerConf(command)
+            CommandOptions.READ_LOG_CMD -> read(command)
+        }
+    }
+
+    var injector = object : Injector {
+        override fun fileOutputStream(file: String) = FileOutputStream(file)
+        override fun readText(file: File) = file.readText()
+        override fun readLogGroups(jarPath: String, className: String) =
+                ProtoLogGroupReader().loadFromJar(jarPath, className)
+        override fun reportParseError(ex: ParsingException) {
+            println("\n${ex.message}\n")
+        }
+    }
+
+    interface Injector {
+        fun fileOutputStream(file: String): OutputStream
+        fun readText(file: File): String
+        fun readLogGroups(jarPath: String, className: String): Map<String, LogGroup>
+        fun reportParseError(ex: ParsingException)
+    }
 }
 
 private fun <T> ExecutorService.submitCallable(f: () -> T) = submit(f)
diff --git a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
index 0ad8091..36ea411 100644
--- a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
@@ -72,7 +72,7 @@
         }
         val ifStmt: IfStmt
         if (group.enabled) {
-            val hash = CodeUtils.hash(fileName, messageString, level, group)
+            val hash = CodeUtils.hash(packagePath, messageString, level, group)
             val newCall = call.clone()
             if (!group.textEnabled) {
                 // Remove message string if text logging is not enabled by default.
@@ -97,7 +97,7 @@
             if (argTypes.size != call.arguments.size - 2) {
                 throw InvalidProtoLogCallException(
                         "Number of arguments (${argTypes.size} does not mach format" +
-                                " string in: $call", ParsingContext(fileName, call))
+                                " string in: $call", ParsingContext(path, call))
             }
             val blockStmt = BlockStmt()
             if (argTypes.isNotEmpty()) {
@@ -214,18 +214,23 @@
             StaticJavaParser.parseExpression<FieldAccessExpr>(protoLogCacheClassName)
     private var processedCode: MutableList<String> = mutableListOf()
     private var offsets: IntArray = IntArray(0)
-    private var fileName: String = ""
+    /** The path of the file being processed, relative to $ANDROID_BUILD_TOP */
+    private var path: String = ""
+    /** The path of the file being processed, relative to the root package */
+    private var packagePath: String = ""
 
     fun processClass(
         code: String,
         path: String,
+        packagePath: String,
         compilationUnit: CompilationUnit =
                StaticJavaParser.parse(code)
     ): String {
-        fileName = path
+        this.path = path
+        this.packagePath = packagePath
         processedCode = code.split('\n').toMutableList()
         offsets = IntArray(processedCode.size)
-        protoLogCallProcessor.process(compilationUnit, this, fileName)
+        protoLogCallProcessor.process(compilationUnit, this, path)
         return processedCode.joinToString("\n")
     }
 }
diff --git a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt
index c100826..175c71f 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt
@@ -46,7 +46,11 @@
     private val statements: MutableMap<Int, LogCall> = mutableMapOf()
     private val groups: MutableSet<LogGroup> = mutableSetOf()
 
-    fun findLogCalls(unit: CompilationUnit, fileName: String): List<Pair<LogCall, ParsingContext>> {
+    fun findLogCalls(
+        unit: CompilationUnit,
+        path: String,
+        packagePath: String
+    ): List<Pair<LogCall, ParsingContext>> {
         val calls = mutableListOf<Pair<LogCall, ParsingContext>>()
         val visitor = object : ProtoLogCallVisitor {
             override fun processCall(
@@ -55,12 +59,12 @@
                 level: LogLevel,
                 group: LogGroup
             ) {
-                val logCall = LogCall(messageString, level, group, fileName)
-                val context = ParsingContext(fileName, call)
+                val logCall = LogCall(messageString, level, group, packagePath)
+                val context = ParsingContext(path, call)
                 calls.add(logCall to context)
             }
         }
-        processor.process(unit, visitor, fileName)
+        processor.process(unit, visitor, path)
 
         return calls
     }
diff --git a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
new file mode 100644
index 0000000..dd8a0b1
--- /dev/null
+++ b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
@@ -0,0 +1,144 @@
+/*
+ * 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.protolog.tool
+
+import org.junit.Assert
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import java.io.ByteArrayInputStream
+import java.io.ByteArrayOutputStream
+import java.io.File
+import java.io.FileNotFoundException
+import java.io.OutputStream
+import java.util.jar.JarInputStream
+
+class EndToEndTest {
+
+    @Test
+    fun e2e_transform() {
+        val output = run(
+                src = "frameworks/base/org/example/Example.java" to """
+                    package org.example;
+                    import com.android.server.protolog.common.ProtoLog;
+                    import static com.android.server.wm.ProtoLogGroup.GROUP;
+
+                    class Example {
+                        void method() {
+                            String argString = "hello";
+                            int argInt = 123;
+                            ProtoLog.d(GROUP, "Example: %s %d", argString, argInt);
+                        }
+                    }
+                """.trimIndent(),
+                logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"),
+                commandOptions = CommandOptions(arrayOf("transform-protolog-calls",
+                        "--protolog-class", "com.android.server.protolog.common.ProtoLog",
+                        "--protolog-impl-class", "com.android.server.protolog.ProtoLogImpl",
+                        "--protolog-cache-class",
+                        "com.android.server.protolog.ProtoLog${"\$\$"}Cache",
+                        "--loggroups-class", "com.android.server.wm.ProtoLogGroup",
+                        "--loggroups-jar", "not_required.jar",
+                        "--output-srcjar", "out.srcjar",
+                        "frameworks/base/org/example/Example.java"))
+        )
+        val outSrcJar = assertLoadSrcJar(output, "out.srcjar")
+        assertTrue(" 2066303299," in outSrcJar["frameworks/base/org/example/Example.java"]!!)
+    }
+
+    @Test
+    fun e2e_viewerConfig() {
+        val output = run(
+                src = "frameworks/base/org/example/Example.java" to """
+                    package org.example;
+                    import com.android.server.protolog.common.ProtoLog;
+                    import static com.android.server.wm.ProtoLogGroup.GROUP;
+
+                    class Example {
+                        void method() {
+                            String argString = "hello";
+                            int argInt = 123;
+                            ProtoLog.d(GROUP, "Example: %s %d", argString, argInt);
+                        }
+                    }
+                """.trimIndent(),
+                logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"),
+                commandOptions = CommandOptions(arrayOf("generate-viewer-config",
+                        "--protolog-class", "com.android.server.protolog.common.ProtoLog",
+                        "--loggroups-class", "com.android.server.wm.ProtoLogGroup",
+                        "--loggroups-jar", "not_required.jar",
+                        "--viewer-conf", "out.json",
+                        "frameworks/base/org/example/Example.java"))
+        )
+        val viewerConfigJson = assertLoadText(output, "out.json")
+        assertTrue("\"2066303299\"" in viewerConfigJson)
+    }
+
+    private fun assertLoadSrcJar(
+        outputs: Map<String, ByteArray>,
+        path: String
+    ): Map<String, String> {
+        val out = outputs[path] ?: fail("$path not in outputs (${outputs.keys})")
+
+        val sources = mutableMapOf<String, String>()
+        JarInputStream(ByteArrayInputStream(out)).use { jarStream ->
+            var entry = jarStream.nextJarEntry
+            while (entry != null) {
+                if (entry.name.endsWith(".java")) {
+                    sources[entry.name] = jarStream.reader().readText()
+                }
+                entry = jarStream.nextJarEntry
+            }
+        }
+        return sources
+    }
+
+    private fun assertLoadText(outputs: Map<String, ByteArray>, path: String): String {
+        val out = outputs[path] ?: fail("$path not in outputs (${outputs.keys})")
+        return out.toString(Charsets.UTF_8)
+    }
+
+    fun run(
+        src: Pair<String, String>,
+        logGroup: LogGroup,
+        commandOptions: CommandOptions
+    ): Map<String, ByteArray> {
+        val outputs = mutableMapOf<String, ByteArrayOutputStream>()
+
+        ProtoLogTool.injector = object : ProtoLogTool.Injector {
+            override fun fileOutputStream(file: String): OutputStream =
+                    ByteArrayOutputStream().also { outputs[file] = it }
+
+            override fun readText(file: File): String {
+                if (file.path == src.first) {
+                    return src.second
+                }
+                throw FileNotFoundException("expected: ${src.first}, but was $file")
+            }
+
+            override fun readLogGroups(jarPath: String, className: String) = mapOf(
+                    logGroup.name to logGroup)
+
+            override fun reportParseError(ex: ParsingException) = throw AssertionError(ex)
+        }
+
+        ProtoLogTool.invoke(commandOptions)
+
+        return outputs.mapValues { it.value.toByteArray() }
+    }
+
+    fun fail(message: String): Nothing = Assert.fail(message) as Nothing
+}
diff --git a/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt
index 6f5955c..4f2be328 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt
@@ -186,7 +186,7 @@
             invocation.arguments[0] as CompilationUnit
         }
 
-        val out = sourceJarWriter.processClass(TEST_CODE, PATH, code)
+        val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code)
         code = StaticJavaParser.parse(out)
 
         val ifStmts = code.findAll(IfStmt::class.java)
@@ -228,7 +228,7 @@
             invocation.arguments[0] as CompilationUnit
         }
 
-        val out = sourceJarWriter.processClass(TEST_CODE_MULTICALLS, PATH, code)
+        val out = sourceJarWriter.processClass(TEST_CODE_MULTICALLS, PATH, PATH, code)
         code = StaticJavaParser.parse(out)
 
         val ifStmts = code.findAll(IfStmt::class.java)
@@ -266,7 +266,7 @@
             invocation.arguments[0] as CompilationUnit
         }
 
-        val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, code)
+        val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code)
         code = StaticJavaParser.parse(out)
 
         val ifStmts = code.findAll(IfStmt::class.java)
@@ -303,7 +303,7 @@
             invocation.arguments[0] as CompilationUnit
         }
 
-        val out = sourceJarWriter.processClass(TEST_CODE_NO_PARAMS, PATH, code)
+        val out = sourceJarWriter.processClass(TEST_CODE_NO_PARAMS, PATH, PATH, code)
         code = StaticJavaParser.parse(out)
 
         val ifStmts = code.findAll(IfStmt::class.java)
@@ -337,7 +337,7 @@
             invocation.arguments[0] as CompilationUnit
         }
 
-        val out = sourceJarWriter.processClass(TEST_CODE, PATH, code)
+        val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code)
         code = StaticJavaParser.parse(out)
 
         val ifStmts = code.findAll(IfStmt::class.java)
@@ -375,7 +375,7 @@
             invocation.arguments[0] as CompilationUnit
         }
 
-        val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, code)
+        val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code)
         code = StaticJavaParser.parse(out)
 
         val ifStmts = code.findAll(IfStmt::class.java)
@@ -413,7 +413,7 @@
             invocation.arguments[0] as CompilationUnit
         }
 
-        val out = sourceJarWriter.processClass(TEST_CODE, PATH, code)
+        val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code)
         code = StaticJavaParser.parse(out)
 
         val ifStmts = code.findAll(IfStmt::class.java)
@@ -439,7 +439,7 @@
             invocation.arguments[0] as CompilationUnit
         }
 
-        val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, code)
+        val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code)
         code = StaticJavaParser.parse(out)
 
         val ifStmts = code.findAll(IfStmt::class.java)
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index 4ce4406..c08f9b0 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -95,7 +95,7 @@
     ],
 }
 
-cc_library_shared {
+cc_library {
     name: "libstatslog",
     host_supported: true,
     generated_sources: ["statslog.cpp"],
diff --git a/wifi/java/android/net/wifi/ISoftApCallback.aidl b/wifi/java/android/net/wifi/ISoftApCallback.aidl
index b8d2971..8a252dd 100644
--- a/wifi/java/android/net/wifi/ISoftApCallback.aidl
+++ b/wifi/java/android/net/wifi/ISoftApCallback.aidl
@@ -16,6 +16,8 @@
 
 package android.net.wifi;
 
+import android.net.wifi.WifiClient;
+
 /**
  * Interface for Soft AP callback.
  *
@@ -36,9 +38,9 @@
     void onStateChanged(int state, int failureReason);
 
     /**
-     * Service to manager callback providing number of connected clients.
+     * Service to manager callback providing connected client's information.
      *
-     * @param numClients number of connected clients
+     * @param clients the currently connected clients
      */
-    void onNumClientsChanged(int numClients);
+    void onConnectedClientsChanged(in List<WifiClient> clients);
 }
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 1337739..023df70 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -34,6 +34,7 @@
 import android.net.wifi.ITxPacketCountListener;
 import android.net.wifi.IOnWifiUsabilityStatsListener;
 import android.net.wifi.ScanResult;
+import android.net.wifi.SoftApConfiguration;
 import android.net.wifi.WifiActivityEnergyInfo;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
@@ -94,6 +95,8 @@
 
     boolean disableNetwork(int netId, String packageName);
 
+    void allowAutojoin(int netId, boolean choice);
+
     boolean startScan(String packageName);
 
     List<ScanResult> getScanResults(String callingPackage);
@@ -140,7 +143,8 @@
 
     boolean stopSoftAp();
 
-    int startLocalOnlyHotspot(in ILocalOnlyHotspotCallback callback, String packageName);
+    int startLocalOnlyHotspot(in ILocalOnlyHotspotCallback callback, String packageName,
+                              in SoftApConfiguration customConfig);
 
     void stopLocalOnlyHotspot();
 
diff --git a/wifi/java/android/net/wifi/IWifiScanner.aidl b/wifi/java/android/net/wifi/IWifiScanner.aidl
index 3984934..114c732 100644
--- a/wifi/java/android/net/wifi/IWifiScanner.aidl
+++ b/wifi/java/android/net/wifi/IWifiScanner.aidl
@@ -26,5 +26,5 @@
 {
     Messenger getMessenger();
 
-    Bundle getAvailableChannels(int band);
+    Bundle getAvailableChannels(int band, String packageName);
 }
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index c0c0361..aa895a6 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -16,11 +16,15 @@
 
 package android.net.wifi;
 
+import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -223,11 +227,86 @@
     */
     public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4;
 
-   /**
-    * AP Channel bandwidth; one of {@link #CHANNEL_WIDTH_20MHZ}, {@link #CHANNEL_WIDTH_40MHZ},
-    * {@link #CHANNEL_WIDTH_80MHZ}, {@link #CHANNEL_WIDTH_160MHZ}
-    * or {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ}.
-    */
+    /**
+     * Wi-Fi unknown standard
+     */
+    public static final int WIFI_STANDARD_UNKNOWN = 0;
+
+    /**
+     * Wi-Fi 802.11a/b/g
+     */
+    public static final int WIFI_STANDARD_LEGACY = 1;
+
+    /**
+     * Wi-Fi 802.11n
+     */
+    public static final int WIFI_STANDARD_11N = 4;
+
+    /**
+     * Wi-Fi 802.11ac
+     */
+    public static final int WIFI_STANDARD_11AC = 5;
+
+    /**
+     * Wi-Fi 802.11ax
+     */
+    public static final int WIFI_STANDARD_11AX = 6;
+
+    /** @hide */
+    @IntDef(prefix = { "WIFI_STANDARD_" }, value = {
+            WIFI_STANDARD_UNKNOWN,
+            WIFI_STANDARD_LEGACY,
+            WIFI_STANDARD_11N,
+            WIFI_STANDARD_11AC,
+            WIFI_STANDARD_11AX
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface WifiStandard{}
+
+    /**
+     * AP wifi standard.
+     */
+    private @WifiStandard int mWifiStandard;
+
+    /**
+     * return the AP wifi standard.
+     */
+    public @WifiStandard int getWifiStandard() {
+        return mWifiStandard;
+    }
+
+    /**
+     * sets the AP wifi standard.
+     * @hide
+     */
+    public void setWifiStandard(@WifiStandard int standard) {
+        mWifiStandard = standard;
+    }
+
+    /**
+     * Convert Wi-Fi standard to string
+     */
+    private static @Nullable String wifiStandardToString(@WifiStandard int standard) {
+        switch(standard) {
+            case WIFI_STANDARD_LEGACY:
+                return "legacy";
+            case WIFI_STANDARD_11N:
+                return "11n";
+            case WIFI_STANDARD_11AC:
+                return "11ac";
+            case WIFI_STANDARD_11AX:
+                return "11ax";
+            case WIFI_STANDARD_UNKNOWN:
+                return "unknown";
+        }
+        return null;
+    }
+
+    /**
+     * AP Channel bandwidth; one of {@link #CHANNEL_WIDTH_20MHZ}, {@link #CHANNEL_WIDTH_40MHZ},
+     * {@link #CHANNEL_WIDTH_80MHZ}, {@link #CHANNEL_WIDTH_160MHZ}
+     * or {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ}.
+     */
     public int channelWidth;
 
     /**
@@ -465,9 +544,16 @@
         public static final int EID_VHT_OPERATION = 192;
         @UnsupportedAppUsage
         public static final int EID_VSA = 221;
+        public static final int EID_EXTENSION_PRESENT = 255;
+
+        /**
+         * Extension IDs
+         */
+        public static final int EID_EXT_HE_OPERATION = 36;
 
         @UnsupportedAppUsage
         public int id;
+        public int idExt;
         @UnsupportedAppUsage
         public byte[] bytes;
 
@@ -476,6 +562,7 @@
 
         public InformationElement(InformationElement rhs) {
             this.id = rhs.id;
+            this.idExt = rhs.idExt;
             this.bytes = rhs.bytes.clone();
         }
     }
@@ -541,6 +628,7 @@
         this.carrierApEapType = UNSPECIFIED;
         this.carrierName = null;
         this.radioChainInfos = null;
+        this.mWifiStandard = WIFI_STANDARD_UNKNOWN;
     }
 
     /** {@hide} */
@@ -563,6 +651,7 @@
         this.carrierApEapType = UNSPECIFIED;
         this.carrierName = null;
         this.radioChainInfos = null;
+        this.mWifiStandard = WIFI_STANDARD_UNKNOWN;
     }
 
     /** {@hide} */
@@ -592,6 +681,7 @@
         this.carrierApEapType = UNSPECIFIED;
         this.carrierName = null;
         this.radioChainInfos = null;
+        this.mWifiStandard = WIFI_STANDARD_UNKNOWN;
     }
 
     /** {@hide} */
@@ -633,6 +723,7 @@
             carrierApEapType = source.carrierApEapType;
             carrierName = source.carrierName;
             radioChainInfos = source.radioChainInfos;
+            this.mWifiStandard = source.mWifiStandard;
         }
     }
 
@@ -671,6 +762,7 @@
         sb.append(", ChannelBandwidth: ").append(channelWidth);
         sb.append(", centerFreq0: ").append(centerFreq0);
         sb.append(", centerFreq1: ").append(centerFreq1);
+        sb.append(", standard: ").append(wifiStandardToString(mWifiStandard));
         sb.append(", 80211mcResponder: ");
         sb.append(((flags & FLAG_80211mc_RESPONDER) != 0) ? "is supported" : "is not supported");
         sb.append(", Carrier AP: ").append(isCarrierAp ? "yes" : "no");
@@ -706,6 +798,7 @@
         dest.writeInt(channelWidth);
         dest.writeInt(centerFreq0);
         dest.writeInt(centerFreq1);
+        dest.writeInt(mWifiStandard);
         dest.writeLong(seen);
         dest.writeInt(untrusted ? 1 : 0);
         dest.writeInt(numUsage);
@@ -717,6 +810,7 @@
             dest.writeInt(informationElements.length);
             for (int i = 0; i < informationElements.length; i++) {
                 dest.writeInt(informationElements[i].id);
+                dest.writeInt(informationElements[i].idExt);
                 dest.writeInt(informationElements[i].bytes.length);
                 dest.writeByteArray(informationElements[i].bytes);
             }
@@ -787,6 +881,7 @@
                                                                fixed with flags below */
                 );
 
+                sr.mWifiStandard = in.readInt();
                 sr.seen = in.readLong();
                 sr.untrusted = in.readInt() != 0;
                 sr.numUsage = in.readInt();
@@ -799,6 +894,7 @@
                     for (int i = 0; i < n; i++) {
                         sr.informationElements[i] = new InformationElement();
                         sr.informationElements[i].id = in.readInt();
+                        sr.informationElements[i].idExt = in.readInt();
                         int len = in.readInt();
                         sr.informationElements[i].bytes = new byte[len];
                         in.readByteArray(sr.informationElements[i].bytes);
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.aidl b/wifi/java/android/net/wifi/SoftApConfiguration.aidl
new file mode 100644
index 0000000..1d06f45
--- /dev/null
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.net.wifi;
+
+parcelable SoftApConfiguration;
\ No newline at end of file
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
new file mode 100644
index 0000000..4cc8653
--- /dev/null
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -0,0 +1,231 @@
+/*
+ * 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.net.wifi;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.net.MacAddress;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * WiFi configuration for a soft access point (a.k.a. Soft AP, SAP, Hotspot).
+ *
+ * This is input for the framework provided by a client app, i.e. it exposes knobs to instruct the
+ * framework how it should open a hotspot.  It is not meant to describe the network as it will be
+ * seen by clients; this role is currently served by {@link WifiConfiguration} (see
+ * {@link WifiManager.LocalOnlyHotspotReservation#getWifiConfiguration()}).
+ *
+ * System apps can use this to configure a local-only hotspot using
+ * {@link WifiManager#startLocalOnlyHotspot(SoftApConfiguration, Executor,
+ * WifiManager.LocalOnlyHotspotCallback)}.
+ *
+ * Instances of this class are immutable; use {@link SoftApConfiguration.Builder} and its methods to
+ * create a new instance.
+ *
+ * @hide
+ */
+@SystemApi
+public final class SoftApConfiguration implements Parcelable {
+    /**
+     * SSID for the AP, or null for a framework-determined SSID.
+     */
+    private final @Nullable String mSsid;
+    /**
+     * BSSID for the AP, or null to use a framework-determined BSSID.
+     */
+    private final @Nullable MacAddress mBssid;
+    /**
+     * Pre-shared key for WPA2-PSK encryption (non-null enables WPA2-PSK).
+     */
+    private final @Nullable String mWpa2Passphrase;
+
+    /** Private constructor for Builder and Parcelable implementation. */
+    private SoftApConfiguration(
+            @Nullable String ssid, @Nullable MacAddress bssid, String wpa2Passphrase) {
+        mSsid = ssid;
+        mBssid = bssid;
+        mWpa2Passphrase = wpa2Passphrase;
+    }
+
+    @Override
+    public boolean equals(Object otherObj) {
+        if (this == otherObj) {
+            return true;
+        }
+        if (!(otherObj instanceof SoftApConfiguration)) {
+            return false;
+        }
+        SoftApConfiguration other = (SoftApConfiguration) otherObj;
+        return Objects.equals(mSsid, other.mSsid)
+                && Objects.equals(mBssid, other.mBssid)
+                && Objects.equals(mWpa2Passphrase, other.mWpa2Passphrase);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mSsid, mBssid, mWpa2Passphrase);
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString(mSsid);
+        dest.writeParcelable(mBssid, flags);
+        dest.writeString(mWpa2Passphrase);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @NonNull
+    public static final Creator<SoftApConfiguration> CREATOR = new Creator<SoftApConfiguration>() {
+        @Override
+        public SoftApConfiguration createFromParcel(Parcel in) {
+            return new SoftApConfiguration(
+                    in.readString(),
+                    in.readParcelable(MacAddress.class.getClassLoader()),
+                    in.readString());
+        }
+
+        @Override
+        public SoftApConfiguration[] newArray(int size) {
+            return new SoftApConfiguration[size];
+        }
+    };
+
+    @Nullable
+    public String getSsid() {
+        return mSsid;
+    }
+
+    @Nullable
+    public MacAddress getBssid() {
+        return mBssid;
+    }
+
+    @Nullable
+    public String getWpa2Passphrase() {
+        return mWpa2Passphrase;
+    }
+
+    /**
+     * Builds a {@link SoftApConfiguration}, which allows an app to configure various aspects of a
+     * Soft AP.
+     *
+     * All fields are optional. By default, SSID and BSSID are automatically chosen by the
+     * framework, and an open network is created.
+     */
+    public static final class Builder {
+        private String mSsid;
+        private MacAddress mBssid;
+        private String mWpa2Passphrase;
+
+        /**
+         * Constructs a Builder with default values (see {@link Builder}).
+         */
+        public Builder() {
+            mSsid = null;
+            mBssid = null;
+            mWpa2Passphrase = null;
+        }
+
+        /**
+         * Constructs a Builder initialized from an existing {@link SoftApConfiguration} instance.
+         */
+        public Builder(@NonNull SoftApConfiguration other) {
+            Objects.requireNonNull(other);
+
+            mSsid = other.mSsid;
+            mBssid = other.mBssid;
+            mWpa2Passphrase = other.mWpa2Passphrase;
+        }
+
+        /**
+         * Builds the {@link SoftApConfiguration}.
+         *
+         * @return A new {@link SoftApConfiguration}, as configured by previous method calls.
+         */
+        @NonNull
+        public SoftApConfiguration build() {
+            return new SoftApConfiguration(mSsid, mBssid, mWpa2Passphrase);
+        }
+
+        /**
+         * Specifies an SSID for the AP.
+         *
+         * @param ssid SSID of valid Unicode characters, or null to have the SSID automatically
+         *             chosen by the framework.
+         * @return Builder for chaining.
+         * @throws IllegalArgumentException when the SSID is empty or not valid Unicode.
+         */
+        @NonNull
+        public Builder setSsid(@Nullable String ssid) {
+            if (ssid != null) {
+                Preconditions.checkStringNotEmpty(ssid);
+                Preconditions.checkArgument(StandardCharsets.UTF_8.newEncoder().canEncode(ssid));
+            }
+            mSsid = ssid;
+            return this;
+        }
+
+        /**
+         * Specifies a BSSID for the AP.
+         *
+         * @param bssid BSSID, or null to have the BSSID chosen by the framework. The caller is
+         *              responsible for avoiding collisions.
+         * @return Builder for chaining.
+         * @throws IllegalArgumentException when the given BSSID is the all-zero or broadcast MAC
+         *                                  address.
+         */
+        @NonNull
+        public Builder setBssid(@Nullable MacAddress bssid) {
+            if (bssid != null) {
+                Preconditions.checkArgument(!bssid.equals(MacAddress.ALL_ZEROS_ADDRESS));
+                Preconditions.checkArgument(!bssid.equals(MacAddress.BROADCAST_ADDRESS));
+            }
+            mBssid = bssid;
+            return this;
+        }
+
+        /**
+         * Specifies that this AP should use WPA2-PSK with the given passphrase.  When set to null
+         * and no other encryption method is configured, an open network is created.
+         *
+         * @param passphrase The passphrase to use, or null to unset a previously-set WPA2-PSK
+         *                   configuration.
+         * @return Builder for chaining.
+         * @throws IllegalArgumentException when the passphrase is the empty string
+         */
+        @NonNull
+        public Builder setWpa2Passphrase(@Nullable String passphrase) {
+            if (passphrase != null) {
+                Preconditions.checkStringNotEmpty(passphrase);
+            }
+            mWpa2Passphrase = passphrase;
+            return this;
+        }
+    }
+}
diff --git a/wifi/java/android/net/wifi/WifiClient.aidl b/wifi/java/android/net/wifi/WifiClient.aidl
new file mode 100644
index 0000000..accdadd
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiClient.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.net.wifi;
+
+@JavaOnlyStableParcelable parcelable WifiClient;
\ No newline at end of file
diff --git a/wifi/java/android/net/wifi/WifiClient.java b/wifi/java/android/net/wifi/WifiClient.java
new file mode 100644
index 0000000..3e09580
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiClient.java
@@ -0,0 +1,97 @@
+/*
+ * 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.net.wifi;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.net.MacAddress;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+
+/** @hide */
+@SystemApi
+public final class WifiClient implements Parcelable {
+
+    private final MacAddress mMacAddress;
+
+    /**
+     * The mac address of this client.
+     */
+    @NonNull
+    public MacAddress getMacAddress() {
+        return mMacAddress;
+    }
+
+    private WifiClient(Parcel in) {
+        mMacAddress = in.readParcelable(null);
+    }
+
+    /** @hide */
+    public WifiClient(@NonNull MacAddress macAddress) {
+        Preconditions.checkNotNull(macAddress, "mMacAddress must not be null.");
+
+        this.mMacAddress = macAddress;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeParcelable(mMacAddress, flags);
+    }
+
+    @NonNull
+    public static final Creator<WifiClient> CREATOR = new Creator<WifiClient>() {
+        public WifiClient createFromParcel(Parcel in) {
+            return new WifiClient(in);
+        }
+
+        public WifiClient[] newArray(int size) {
+            return new WifiClient[size];
+        }
+    };
+
+    @NonNull
+    @Override
+    public String toString() {
+        return "WifiClient{"
+                + "mMacAddress=" + mMacAddress
+                + '}';
+    }
+
+    @Override
+    public boolean equals(@NonNull Object o) {
+        if (this == o) return true;
+        if (!(o instanceof WifiClient)) return false;
+        WifiClient client = (WifiClient) o;
+        return mMacAddress.equals(client.mMacAddress);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mMacAddress);
+    }
+}
+
+
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 2afb14a..30c24d3 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -34,6 +34,7 @@
 import android.os.Parcelable;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.BackupUtils;
 import android.util.Log;
@@ -730,11 +731,27 @@
     public String lastUpdateName;
 
     /**
+     * The carrier ID identifies the operator who provides this network configuration.
+     *    see {@link TelephonyManager#getSimCarrierId()}
+     * @hide
+     */
+    @SystemApi
+    public int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
+
+    /**
      * @hide
      * Status of user approval for connection
      */
     public int userApproved = USER_UNSPECIFIED;
 
+    /**
+     * @hide
+     * Auto-join is allowed by user for this network.
+     * Default true.
+     */
+    @SystemApi
+    public boolean allowAutojoin = true;
+
     /** The Below RSSI thresholds are used to configure AutoJoin
      *  - GOOD/LOW/BAD thresholds are used so as to calculate link score
      *  - UNWANTED_SOFT are used by the blacklisting logic so as to handle
@@ -1038,10 +1055,10 @@
 
     /**
      * @hide
-     * The wall clock time of when |mRandomizedMacAddress| last changed.
-     * Used to determine when we should re-randomize in aggressive mode.
+     * The wall clock time of when |mRandomizedMacAddress| should be re-randomized in aggressive
+     * randomization mode.
      */
-    public long randomizedMacLastModifiedTimeMs = 0;
+    public long randomizedMacExpirationTimeMs = 0;
 
     /**
      * @hide
@@ -1842,6 +1859,7 @@
                 .append(" PRIO: ").append(this.priority)
                 .append(" HIDDEN: ").append(this.hiddenSSID)
                 .append(" PMF: ").append(this.requirePMF)
+                .append("CarrierId: ").append(this.carrierId)
                 .append('\n');
 
 
@@ -1902,8 +1920,9 @@
         }
         sbuf.append(" macRandomizationSetting: ").append(macRandomizationSetting).append("\n");
         sbuf.append(" mRandomizedMacAddress: ").append(mRandomizedMacAddress).append("\n");
-        sbuf.append(" randomizedMacLastModifiedTimeMs: ").append(randomizedMacLastModifiedTimeMs)
-                .append("\n");
+        sbuf.append(" randomizedMacExpirationTimeMs: ")
+                .append(randomizedMacExpirationTimeMs == 0 ? "<none>"
+                        : TimeUtils.logTimeOfDay(randomizedMacExpirationTimeMs)).append("\n");
         sbuf.append(" KeyMgmt:");
         for (int k = 0; k < this.allowedKeyManagement.size(); k++) {
             if (this.allowedKeyManagement.get(k)) {
@@ -2022,6 +2041,7 @@
         if (updateIdentifier != null) sbuf.append(" updateIdentifier=" + updateIdentifier);
         sbuf.append(" lcuid=" + lastConnectUid);
         sbuf.append(" userApproved=" + userApprovedAsString(userApproved));
+        sbuf.append(" allowAutojoin=" + allowAutojoin);
         sbuf.append(" noInternetAccessExpected=" + noInternetAccessExpected);
         sbuf.append(" ");
 
@@ -2421,6 +2441,7 @@
             numScorerOverrideAndSwitchedNetwork = source.numScorerOverrideAndSwitchedNetwork;
             numAssociation = source.numAssociation;
             userApproved = source.userApproved;
+            allowAutojoin = source.allowAutojoin;
             numNoInternetAccessReports = source.numNoInternetAccessReports;
             noInternetAccessExpected = source.noInternetAccessExpected;
             creationTime = source.creationTime;
@@ -2429,9 +2450,10 @@
             recentFailure.setAssociationStatus(source.recentFailure.getAssociationStatus());
             mRandomizedMacAddress = source.mRandomizedMacAddress;
             macRandomizationSetting = source.macRandomizationSetting;
-            randomizedMacLastModifiedTimeMs = source.randomizedMacLastModifiedTimeMs;
+            randomizedMacExpirationTimeMs = source.randomizedMacExpirationTimeMs;
             requirePMF = source.requirePMF;
             updateIdentifier = source.updateIdentifier;
+            carrierId = source.carrierId;
         }
     }
 
@@ -2496,6 +2518,7 @@
         dest.writeInt(numScorerOverrideAndSwitchedNetwork);
         dest.writeInt(numAssociation);
         dest.writeInt(userApproved);
+        dest.writeBoolean(allowAutojoin);
         dest.writeInt(numNoInternetAccessReports);
         dest.writeInt(noInternetAccessExpected ? 1 : 0);
         dest.writeInt(shared ? 1 : 0);
@@ -2504,7 +2527,8 @@
         dest.writeParcelable(mRandomizedMacAddress, flags);
         dest.writeInt(macRandomizationSetting);
         dest.writeInt(osu ? 1 : 0);
-        dest.writeLong(randomizedMacLastModifiedTimeMs);
+        dest.writeLong(randomizedMacExpirationTimeMs);
+        dest.writeInt(carrierId);
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -2571,6 +2595,7 @@
                 config.numScorerOverrideAndSwitchedNetwork = in.readInt();
                 config.numAssociation = in.readInt();
                 config.userApproved = in.readInt();
+                config.allowAutojoin = in.readBoolean();
                 config.numNoInternetAccessReports = in.readInt();
                 config.noInternetAccessExpected = in.readInt() != 0;
                 config.shared = in.readInt() != 0;
@@ -2579,7 +2604,8 @@
                 config.mRandomizedMacAddress = in.readParcelable(null);
                 config.macRandomizationSetting = in.readInt();
                 config.osu = in.readInt() != 0;
-                config.randomizedMacLastModifiedTimeMs = in.readLong();
+                config.randomizedMacExpirationTimeMs = in.readLong();
+                config.carrierId = in.readInt();
                 return config;
             }
 
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index f8c2011..7b99a2b 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -1263,4 +1263,23 @@
     public @Ocsp int getOcsp() {
         return mOcsp;
     }
+
+    /**
+     * If the current authentication method needs SIM card.
+     * @return true if the credential information require SIM card for current authentication
+     * method, otherwise it returns false.
+     * @hide
+     */
+    public boolean requireSimCredential() {
+        if (mEapMethod == Eap.SIM || mEapMethod == Eap.AKA || mEapMethod == Eap.AKA_PRIME) {
+            return true;
+        }
+        if (mEapMethod == Eap.PEAP) {
+            if (mPhase2Method == Phase2.SIM || mPhase2Method == Phase2.AKA
+                    || mPhase2Method == Phase2.AKA_PRIME) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 62ba95d..86e5122 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -16,7 +16,6 @@
 
 package android.net.wifi;
 
-import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -28,8 +27,6 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 import java.net.Inet4Address;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
@@ -99,45 +96,9 @@
     private int mRssi;
 
     /**
-     * Wi-Fi unknown technology
+     * Wi-Fi standard for the connection
      */
-    public static final int WIFI_TECHNOLOGY_UNKNOWN = 0;
-
-    /**
-     * Wi-Fi 802.11a/b/g
-     */
-    public static final int WIFI_TECHNOLOGY_LEGACY = 1;
-
-    /**
-     * Wi-Fi 802.11n
-     */
-    public static final int WIFI_TECHNOLOGY_11N = 4;
-
-    /**
-     * Wi-Fi 802.11ac
-     */
-    public static final int WIFI_TECHNOLOGY_11AC = 5;
-
-    /**
-     * Wi-Fi 802.11ax
-     */
-    public static final int WIFI_TECHNOLOGY_11AX = 6;
-
-    /** @hide */
-    @IntDef(prefix = { "WIFI_TECHNOLOGY_" }, value = {
-            WIFI_TECHNOLOGY_UNKNOWN,
-            WIFI_TECHNOLOGY_LEGACY,
-            WIFI_TECHNOLOGY_11N,
-            WIFI_TECHNOLOGY_11AC,
-            WIFI_TECHNOLOGY_11AX
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface WifiTechnology{}
-
-    /**
-     * Wi-Fi technology for the connection
-     */
-    private @WifiTechnology int mWifiTechnology;
+    private @ScanResult.WifiStandard int mWifiStandard;
 
     /**
      * The unit in which links speeds are expressed.
@@ -330,7 +291,7 @@
             txSuccessRate = source.txSuccessRate;
             rxSuccessRate = source.rxSuccessRate;
             score = source.score;
-            mWifiTechnology = source.mWifiTechnology;
+            mWifiStandard = source.mWifiStandard;
         }
     }
 
@@ -419,19 +380,19 @@
     }
 
     /**
-     * Sets the Wi-Fi technology
+     * Sets the Wi-Fi standard
      * @hide
      */
-    public void setWifiTechnology(@WifiTechnology int wifiTechnology) {
-        mWifiTechnology = wifiTechnology;
+    public void setWifiStandard(@ScanResult.WifiStandard int wifiStandard) {
+        mWifiStandard = wifiStandard;
     }
 
     /**
-     * Get connection Wi-Fi technology
-     * @return the connection Wi-Fi technology
+     * Get connection Wi-Fi standard
+     * @return the connection Wi-Fi standard
      */
-    public @WifiTechnology int getWifiTechnology() {
-        return mWifiTechnology;
+    public @ScanResult.WifiStandard int getWifiStandard() {
+        return mWifiStandard;
     }
 
     /**
@@ -740,7 +701,7 @@
                 .append(", MAC: ").append(mMacAddress == null ? none : mMacAddress)
                 .append(", Supplicant state: ")
                 .append(mSupplicantState == null ? none : mSupplicantState)
-                .append(", Wi-Fi technology: ").append(mWifiTechnology)
+                .append(", Wi-Fi standard: ").append(mWifiStandard)
                 .append(", RSSI: ").append(mRssi)
                 .append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS)
                 .append(", Tx Link speed: ").append(mTxLinkSpeed).append(LINK_SPEED_UNITS)
@@ -796,7 +757,7 @@
         dest.writeString(mNetworkSuggestionOrSpecifierPackageName);
         dest.writeString(mFqdn);
         dest.writeString(mProviderFriendlyName);
-        dest.writeInt(mWifiTechnology);
+        dest.writeInt(mWifiStandard);
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -838,7 +799,7 @@
                 info.mNetworkSuggestionOrSpecifierPackageName = in.readString();
                 info.mFqdn = in.readString();
                 info.mProviderFriendlyName = in.readString();
-                info.mWifiTechnology = in.readInt();
+                info.mWifiStandard = in.readInt();
                 return info;
             }
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 04b073b..07831c7 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -71,6 +71,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.Executor;
 
@@ -530,7 +531,9 @@
     @SystemApi
     public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
     /**
-     * The interface used for the softap.
+     * The lookup key for a String extra that stores the interface name used for the Soft AP.
+     * This extra is included in the broadcast {@link #WIFI_AP_STATE_CHANGED_ACTION}.
+     * Retrieve its value with {@link android.content.Intent#getStringExtra(String)}.
      *
      * @hide
      */
@@ -538,9 +541,10 @@
     public static final String EXTRA_WIFI_AP_INTERFACE_NAME =
             "android.net.wifi.extra.WIFI_AP_INTERFACE_NAME";
     /**
-     * The intended ip mode for this softap.
-     * @see #IFACE_IP_MODE_TETHERED
-     * @see #IFACE_IP_MODE_LOCAL_ONLY
+     * The lookup key for an int extra that stores the intended IP mode for this Soft AP.
+     * One of {@link #IFACE_IP_MODE_TETHERED} or {@link #IFACE_IP_MODE_LOCAL_ONLY}.
+     * This extra is included in the broadcast {@link #WIFI_AP_STATE_CHANGED_ACTION}.
+     * Retrieve its value with {@link android.content.Intent#getIntExtra(String, int)}.
      *
      * @hide
      */
@@ -2151,69 +2155,69 @@
     }
 
     /** @hide */
-    public static final int WIFI_FEATURE_INFRA            = 0x0001;  // Basic infrastructure mode
+    public static final long WIFI_FEATURE_INFRA            = 0x0001L;  // Basic infrastructure mode
     /** @hide */
-    public static final int WIFI_FEATURE_INFRA_5G         = 0x0002;  // Support for 5 GHz Band
+    public static final long WIFI_FEATURE_INFRA_5G         = 0x0002L;  // Support for 5 GHz Band
     /** @hide */
-    public static final int WIFI_FEATURE_PASSPOINT        = 0x0004;  // Support for GAS/ANQP
+    public static final long WIFI_FEATURE_PASSPOINT        = 0x0004L;  // Support for GAS/ANQP
     /** @hide */
-    public static final int WIFI_FEATURE_P2P              = 0x0008;  // Wifi-Direct
+    public static final long WIFI_FEATURE_P2P              = 0x0008L;  // Wifi-Direct
     /** @hide */
-    public static final int WIFI_FEATURE_MOBILE_HOTSPOT   = 0x0010;  // Soft AP
+    public static final long WIFI_FEATURE_MOBILE_HOTSPOT   = 0x0010L;  // Soft AP
     /** @hide */
-    public static final int WIFI_FEATURE_SCANNER          = 0x0020;  // WifiScanner APIs
+    public static final long WIFI_FEATURE_SCANNER          = 0x0020L;  // WifiScanner APIs
     /** @hide */
-    public static final int WIFI_FEATURE_AWARE            = 0x0040;  // Wi-Fi AWare networking
+    public static final long WIFI_FEATURE_AWARE            = 0x0040L;  // Wi-Fi AWare networking
     /** @hide */
-    public static final int WIFI_FEATURE_D2D_RTT          = 0x0080;  // Device-to-device RTT
+    public static final long WIFI_FEATURE_D2D_RTT          = 0x0080L;  // Device-to-device RTT
     /** @hide */
-    public static final int WIFI_FEATURE_D2AP_RTT         = 0x0100;  // Device-to-AP RTT
+    public static final long WIFI_FEATURE_D2AP_RTT         = 0x0100L;  // Device-to-AP RTT
     /** @hide */
-    public static final int WIFI_FEATURE_BATCH_SCAN       = 0x0200;  // Batched Scan (deprecated)
+    public static final long WIFI_FEATURE_BATCH_SCAN       = 0x0200L;  // Batched Scan (deprecated)
     /** @hide */
-    public static final int WIFI_FEATURE_PNO              = 0x0400;  // Preferred network offload
+    public static final long WIFI_FEATURE_PNO              = 0x0400L;  // Preferred network offload
     /** @hide */
-    public static final int WIFI_FEATURE_ADDITIONAL_STA   = 0x0800;  // Support for two STAs
+    public static final long WIFI_FEATURE_ADDITIONAL_STA   = 0x0800L;  // Support for two STAs
     /** @hide */
-    public static final int WIFI_FEATURE_TDLS             = 0x1000;  // Tunnel directed link setup
+    public static final long WIFI_FEATURE_TDLS             = 0x1000L;  // Tunnel directed link setup
     /** @hide */
-    public static final int WIFI_FEATURE_TDLS_OFFCHANNEL  = 0x2000;  // Support for TDLS off channel
+    public static final long WIFI_FEATURE_TDLS_OFFCHANNEL  = 0x2000L;  // TDLS off channel
     /** @hide */
-    public static final int WIFI_FEATURE_EPR              = 0x4000;  // Enhanced power reporting
+    public static final long WIFI_FEATURE_EPR              = 0x4000L;  // Enhanced power reporting
     /** @hide */
-    public static final int WIFI_FEATURE_AP_STA           = 0x8000;  // AP STA Concurrency
+    public static final long WIFI_FEATURE_AP_STA           = 0x8000L;  // AP STA Concurrency
     /** @hide */
-    public static final int WIFI_FEATURE_LINK_LAYER_STATS = 0x10000; // Link layer stats collection
+    public static final long WIFI_FEATURE_LINK_LAYER_STATS = 0x10000L; // Link layer stats
     /** @hide */
-    public static final int WIFI_FEATURE_LOGGER           = 0x20000; // WiFi Logger
+    public static final long WIFI_FEATURE_LOGGER           = 0x20000L; // WiFi Logger
     /** @hide */
-    public static final int WIFI_FEATURE_HAL_EPNO         = 0x40000; // Enhanced PNO
+    public static final long WIFI_FEATURE_HAL_EPNO         = 0x40000L; // Enhanced PNO
     /** @hide */
-    public static final int WIFI_FEATURE_RSSI_MONITOR     = 0x80000; // RSSI Monitor
+    public static final long WIFI_FEATURE_RSSI_MONITOR     = 0x80000L; // RSSI Monitor
     /** @hide */
-    public static final int WIFI_FEATURE_MKEEP_ALIVE      = 0x100000; // mkeep_alive
+    public static final long WIFI_FEATURE_MKEEP_ALIVE      = 0x100000L; // mkeep_alive
     /** @hide */
-    public static final int WIFI_FEATURE_CONFIG_NDO       = 0x200000; // ND offload
+    public static final long WIFI_FEATURE_CONFIG_NDO       = 0x200000L; // ND offload
     /** @hide */
-    public static final int WIFI_FEATURE_TRANSMIT_POWER   = 0x400000; // Capture transmit power
+    public static final long WIFI_FEATURE_TRANSMIT_POWER   = 0x400000L; // Capture transmit power
     /** @hide */
-    public static final int WIFI_FEATURE_CONTROL_ROAMING  = 0x800000; // Control firmware roaming
+    public static final long WIFI_FEATURE_CONTROL_ROAMING  = 0x800000L; // Control firmware roaming
     /** @hide */
-    public static final int WIFI_FEATURE_IE_WHITELIST     = 0x1000000; // Probe IE white listing
+    public static final long WIFI_FEATURE_IE_WHITELIST     = 0x1000000L; // Probe IE white listing
     /** @hide */
-    public static final int WIFI_FEATURE_SCAN_RAND        = 0x2000000; // Random MAC & Probe seq
+    public static final long WIFI_FEATURE_SCAN_RAND        = 0x2000000L; // Random MAC & Probe seq
     /** @hide */
-    public static final int WIFI_FEATURE_TX_POWER_LIMIT   = 0x4000000; // Set Tx power limit
+    public static final long WIFI_FEATURE_TX_POWER_LIMIT   = 0x4000000L; // Set Tx power limit
     /** @hide */
-    public static final int WIFI_FEATURE_WPA3_SAE         = 0x8000000; // WPA3-Personal SAE
+    public static final long WIFI_FEATURE_WPA3_SAE         = 0x8000000L; // WPA3-Personal SAE
     /** @hide */
-    public static final int WIFI_FEATURE_WPA3_SUITE_B     = 0x10000000; // WPA3-Enterprise Suite-B
+    public static final long WIFI_FEATURE_WPA3_SUITE_B     = 0x10000000L; // WPA3-Enterprise Suite-B
     /** @hide */
-    public static final int WIFI_FEATURE_OWE              = 0x20000000; // Enhanced Open
+    public static final long WIFI_FEATURE_OWE              = 0x20000000L; // Enhanced Open
     /** @hide */
-    public static final int WIFI_FEATURE_LOW_LATENCY      = 0x40000000; // Low Latency modes
+    public static final long WIFI_FEATURE_LOW_LATENCY      = 0x40000000L; // Low Latency modes
     /** @hide */
-    public static final int WIFI_FEATURE_DPP              = 0x80000000; // DPP (Easy-Connect)
+    public static final long WIFI_FEATURE_DPP              = 0x80000000L; // DPP (Easy-Connect)
     /** @hide */
     public static final long WIFI_FEATURE_P2P_RAND_MAC    = 0x100000000L; // Random P2P MAC
 
@@ -2697,12 +2701,13 @@
     }
 
     /**
-     * Start SoftAp mode with the specified configuration.
-     * Note that starting in access point mode disables station
-     * mode operation
-     * @param wifiConfig SSID, security and channel details as
-     *        part of WifiConfiguration
-     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     * Start Soft AP (hotspot) mode with the specified configuration.
+     * Note that starting Soft AP mode may disable station mode operation if the device does not
+     * support concurrency.
+     * @param wifiConfig SSID, security and channel details as part of WifiConfiguration, or null to
+     *                   use the persisted Soft AP configuration that was previously set using
+     *                   {@link #setWifiApConfiguration(WifiConfiguration)}.
+     * @return {@code true} if the operation succeeded, {@code false} otherwise
      *
      * @hide
      */
@@ -2743,13 +2748,6 @@
         }
     }
 
-    private Executor executorForHandler(@Nullable Handler handler) {
-        if (handler == null) {
-            return mContext.getMainExecutor();
-        }
-        return new HandlerExecutor(handler);
-    }
-
     /**
      * Request a local only hotspot that an application can use to communicate between co-located
      * devices connected to the created WiFi hotspot.  The network created by this method will not
@@ -2805,9 +2803,59 @@
      * @param handler Handler to be used for callbacks.  If the caller passes a null Handler, the
      * main thread will be used.
      */
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.CHANGE_WIFI_STATE,
+            android.Manifest.permission.ACCESS_FINE_LOCATION})
     public void startLocalOnlyHotspot(LocalOnlyHotspotCallback callback,
             @Nullable Handler handler) {
-        Executor executor = executorForHandler(handler);
+        Executor executor = handler == null ? null : new HandlerExecutor(handler);
+        startLocalOnlyHotspotInternal(null, executor, callback);
+    }
+
+    /**
+     * Starts a local-only hotspot with a specific configuration applied. See
+     * {@link #startLocalOnlyHotspot(LocalOnlyHotspotCallback, Handler)}.
+     *
+     * Applications need either {@link android.Manifest.permission#NETWORK_SETUP_WIZARD} or
+     * {@link android.Manifest.permission#NETWORK_SETTINGS} to call this method.
+     *
+     * Since custom configuration settings may be incompatible with each other, the hotspot started
+     * through this method cannot coexist with another hotspot created through
+     * startLocalOnlyHotspot. If this is attempted, the first hotspot request wins and others
+     * receive {@link LocalOnlyHotspotCallback#ERROR_GENERIC} through
+     * {@link LocalOnlyHotspotCallback#onFailed}.
+     *
+     * @param config Custom configuration for the hotspot. See {@link SoftApConfiguration}.
+     * @param executor Executor to run callback methods on, or null to use the main thread.
+     * @param callback Callback object for updates about hotspot status, or null for no updates.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD})
+    public void startLocalOnlyHotspot(@NonNull SoftApConfiguration config,
+            @Nullable Executor executor,
+            @Nullable LocalOnlyHotspotCallback callback) {
+        Objects.requireNonNull(config);
+        startLocalOnlyHotspotInternal(config, executor, callback);
+    }
+
+    /**
+     * Common implementation of both configurable and non-configurable LOHS.
+     *
+     * @param config App-specified configuration, or null. When present, additional privileges are
+     *               required, and the hotspot cannot be shared with other clients.
+     * @param executor Executor to run callback methods on, or null to use the main thread.
+     * @param callback Callback object for updates about hotspot status, or null for no updates.
+     */
+    private void startLocalOnlyHotspotInternal(
+            @Nullable SoftApConfiguration config,
+            @Nullable Executor executor,
+            @Nullable LocalOnlyHotspotCallback callback) {
+        if (executor == null) {
+            executor = mContext.getMainExecutor();
+        }
         synchronized (mLock) {
             LocalOnlyHotspotCallbackProxy proxy =
                     new LocalOnlyHotspotCallbackProxy(this, executor, callback);
@@ -2817,7 +2865,7 @@
                     throw new RemoteException("Wifi service is not running");
                 }
                 String packageName = mContext.getOpPackageName();
-                int returnCode = iWifiManager.startLocalOnlyHotspot(proxy, packageName);
+                int returnCode = iWifiManager.startLocalOnlyHotspot(proxy, packageName, config);
                 if (returnCode != LocalOnlyHotspotCallback.REQUEST_REGISTERED) {
                     // Send message to the proxy to make sure we call back on the correct thread
                     proxy.onHotspotFailed(returnCode);
@@ -2898,7 +2946,8 @@
      */
     public void watchLocalOnlyHotspot(LocalOnlyHotspotObserver observer,
             @Nullable Handler handler) {
-        Executor executor = executorForHandler(handler);
+        Executor executor = handler == null ? mContext.getMainExecutor()
+                : new HandlerExecutor(handler);
         synchronized (mLock) {
             mLOHSObserverProxy =
                     new LocalOnlyHotspotObserverProxy(this, executor, observer);
@@ -3250,21 +3299,22 @@
         /**
          * Called when soft AP state changes.
          *
-         * @param state new new AP state. One of {@link #WIFI_AP_STATE_DISABLED},
-         *        {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
-         *        {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
+         * @param state         new new AP state. One of {@link #WIFI_AP_STATE_DISABLED},
+         *                      {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
+         *                      {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
          * @param failureReason reason when in failed state. One of
-         *        {@link #SAP_START_FAILURE_GENERAL}, {@link #SAP_START_FAILURE_NO_CHANNEL}
+         *                      {@link #SAP_START_FAILURE_GENERAL},
+         *                      {@link #SAP_START_FAILURE_NO_CHANNEL}
          */
-        public abstract void onStateChanged(@WifiApState int state,
+        void onStateChanged(@WifiApState int state,
                 @SapStartFailure int failureReason);
 
         /**
-         * Called when number of connected clients to soft AP changes.
+         * Called when the connected clients to soft AP changes.
          *
-         * @param numClients number of connected clients
+         * @param clients the currently connected clients
          */
-        public abstract void onNumClientsChanged(int numClients);
+        void onConnectedClientsChanged(@NonNull List<WifiClient> clients);
     }
 
     /**
@@ -3287,18 +3337,21 @@
                 Log.v(TAG, "SoftApCallbackProxy: onStateChanged: state=" + state
                         + ", failureReason=" + failureReason);
             }
+
             mHandler.post(() -> {
                 mCallback.onStateChanged(state, failureReason);
             });
         }
 
         @Override
-        public void onNumClientsChanged(int numClients) {
+        public void onConnectedClientsChanged(List<WifiClient> clients) {
             if (mVerboseLoggingEnabled) {
-                Log.v(TAG, "SoftApCallbackProxy: onNumClientsChanged: numClients=" + numClients);
+                Log.v(TAG, "SoftApCallbackProxy: onConnectedClientsChanged: clients="
+                        + clients.size() + " clients");
             }
+
             mHandler.post(() -> {
-                mCallback.onNumClientsChanged(numClients);
+                mCallback.onConnectedClientsChanged(clients);
             });
         }
     }
@@ -3476,10 +3529,12 @@
          *
          * @param manager WifiManager
          * @param executor Executor for delivering callbacks.
-         * @param callback LocalOnlyHotspotCallback to notify the calling application.
+         * @param callback LocalOnlyHotspotCallback to notify the calling application, or null.
          */
-        LocalOnlyHotspotCallbackProxy(WifiManager manager, Executor executor,
-                                      LocalOnlyHotspotCallback callback) {
+        LocalOnlyHotspotCallbackProxy(
+                @NonNull WifiManager manager,
+                @NonNull Executor executor,
+                @Nullable LocalOnlyHotspotCallback callback) {
             mWifiManager = new WeakReference<>(manager);
             mExecutor = executor;
             mCallback = callback;
@@ -3497,6 +3552,7 @@
             }
             final LocalOnlyHotspotReservation reservation =
                     manager.new LocalOnlyHotspotReservation(config);
+            if (mCallback == null) return;
             mExecutor.execute(() -> mCallback.onStarted(reservation));
         }
 
@@ -3506,6 +3562,7 @@
             if (manager == null) return;
 
             Log.w(TAG, "LocalOnlyHotspotCallbackProxy: hotspot stopped");
+            if (mCallback == null) return;
             mExecutor.execute(() -> mCallback.onStopped());
         }
 
@@ -3516,6 +3573,7 @@
 
             Log.w(TAG, "LocalOnlyHotspotCallbackProxy: failed to start.  reason: "
                     + reason);
+            if (mCallback == null) return;
             mExecutor.execute(() -> mCallback.onFailed(reason));
         }
     }
@@ -3865,6 +3923,29 @@
     }
 
     /**
+     * Sets the user choice for allowing auto-join to a network.
+     * The updated choice will be made available through the updated config supplied by the
+     * CONFIGURED_NETWORKS_CHANGED broadcast.
+     *
+     * @param netId the id of the network to allow/disallow autojoin for.
+     * @param choice true to allow autojoin, false to disallow autojoin
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+    public void allowAutojoin(int netId, boolean choice) {
+        try {
+            IWifiManager iWifiManager = getIWifiManager();
+            if (iWifiManager == null) {
+                throw new RemoteException("Wifi service is not running");
+            }
+            iWifiManager.allowAutojoin(netId, choice);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Disable ephemeral Network
      *
      * @param SSID, in the format of WifiConfiguration's SSID.
@@ -5159,16 +5240,18 @@
     /**
      * Add a listener for Scan Results. See {@link ScanResultsListener}.
      * Caller will receive the event when scan results are available.
-     * Caller should use {@link WifiManager#getScanResults()} to get the scan results.
+     * Caller should use {@link WifiManager#getScanResults()} requires
+     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} to get the scan results.
      * Caller can remove a previously registered listener using
      * {@link WifiManager#removeScanResultsListener(ScanResultsListener)}
+     * Same caller can add multiple listeners.
      * <p>
      * Applications should have the
      * {@link android.Manifest.permission#ACCESS_WIFI_STATE} permission. Callers
      * without the permission will trigger a {@link java.lang.SecurityException}.
      * <p>
      *
-     * @param executor  The executor to execute the listener of the {@code listener} object.
+     * @param executor The executor to execute the listener of the {@code listener} object.
      * @param listener listener for Scan Results events
      */
 
@@ -5186,7 +5269,7 @@
             iWifiManager.registerScanResultsListener(
                     new Binder(),
                     new ScanResultsListenerProxy(executor, listener),
-                    mContext.getOpPackageName().hashCode());
+                    listener.hashCode());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -5208,7 +5291,7 @@
             if (iWifiManager == null) {
                 throw new RemoteException("Wifi service is not running");
             }
-            iWifiManager.unregisterScanResultsListener(mContext.getOpPackageName().hashCode());
+            iWifiManager.unregisterScanResultsListener(listener.hashCode());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 9b529ce..246e96f 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -21,12 +21,15 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.app.ActivityThread;
 import android.net.MacAddress;
 import android.net.wifi.hotspot2.PasspointConfiguration;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.Process;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 
 import java.nio.charset.CharsetEncoder;
@@ -107,6 +110,12 @@
          */
         private int mPriority;
 
+        /**
+         * The carrier ID identifies the operator who provides this network configuration.
+         *    see {@link TelephonyManager#getSimCarrierId()}
+         */
+        private int mCarrierId;
+
         public Builder() {
             mSsid = null;
             mBssid =  null;
@@ -121,6 +130,7 @@
             mIsUserInteractionRequired = false;
             mIsMetered = false;
             mPriority = UNASSIGNED_PRIORITY;
+            mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
         }
 
         /**
@@ -258,6 +268,23 @@
         }
 
         /**
+         * Set the carrier ID of the network operator. The carrier ID associates a Suggested
+         * network with a specific carrier (and therefore SIM). The carrier ID must be provided
+         * for any network which uses the SIM-based authentication: e.g. EAP-SIM, EAP-AKA,
+         * EAP-AKA', and EAP-PEAP with SIM-based phase 2 authentication.
+         * @param carrierId see {@link TelephonyManager#getSimCarrierId()}.
+         * @return Instance of {@link Builder} to enable chaining of the builder method.
+         *
+         * @hide
+         */
+        @SystemApi
+        @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING)
+        public @NonNull Builder setCarrierId(int carrierId) {
+            mCarrierId = carrierId;
+            return this;
+        }
+
+        /**
          * Specifies whether this represents a hidden network.
          * <p>
          * <li>If not set, defaults to false (i.e not a hidden network).</li>
@@ -380,6 +407,7 @@
             wifiConfiguration.meteredOverride =
                     mIsMetered ? WifiConfiguration.METERED_OVERRIDE_METERED
                             : WifiConfiguration.METERED_OVERRIDE_NONE;
+            wifiConfiguration.carrierId = mCarrierId;
             return wifiConfiguration;
         }
 
@@ -405,6 +433,7 @@
             wifiConfiguration.meteredOverride =
                     mIsMetered ? WifiConfiguration.METERED_OVERRIDE_METERED
                             : WifiConfiguration.METERED_OVERRIDE_NONE;
+            mPasspointConfiguration.setCarrierId(mCarrierId);
             return wifiConfiguration;
         }
 
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 68948cb..67993e1 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -17,6 +17,7 @@
 package android.net.wifi;
 
 import android.Manifest;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
@@ -39,6 +40,8 @@
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.Protocol;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -51,26 +54,38 @@
 @SystemService(Context.WIFI_SCANNING_SERVICE)
 public class WifiScanner {
 
-    /** no band specified; use channel list instead */
-    public static final int WIFI_BAND_UNSPECIFIED = 0;      /* not specified */
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"WIFI_BAND_"}, value = {
+            WIFI_BAND_UNSPECIFIED,
+            WIFI_BAND_24_GHZ,
+            WIFI_BAND_5_GHZ,
+            WIFI_BAND_BOTH,
+            WIFI_BAND_5_GHZ_DFS_ONLY,
+            WIFI_BAND_24_GHZ_WITH_5GHZ_DFS,
+            WIFI_BAND_5_GHZ_WITH_DFS,
+            WIFI_BAND_BOTH_WITH_DFS})
+    public @interface WifiBand {}
 
+    /** no band specified; use channel list instead */
+    public static final int WIFI_BAND_UNSPECIFIED = 0;
     /** 2.4 GHz band */
-    public static final int WIFI_BAND_24_GHZ = 1;           /* 2.4 GHz band */
+    public static final int WIFI_BAND_24_GHZ = 1;
     /** 5 GHz band excluding DFS channels */
-    public static final int WIFI_BAND_5_GHZ = 2;            /* 5 GHz band without DFS channels */
+    public static final int WIFI_BAND_5_GHZ = 2;
+    /** Both 2.4 GHz band and 5 GHz band; no DFS channels */
+    public static final int WIFI_BAND_BOTH = 3;
     /** DFS channels from 5 GHz band only */
-    public static final int WIFI_BAND_5_GHZ_DFS_ONLY  = 4;  /* 5 GHz band DFS channels */
+    public static final int WIFI_BAND_5_GHZ_DFS_ONLY  = 4;
     /**
      * 2.4Ghz band + DFS channels from 5 GHz band only
      * @hide
      */
     public static final int WIFI_BAND_24_GHZ_WITH_5GHZ_DFS  = 5;
     /** 5 GHz band including DFS channels */
-    public static final int WIFI_BAND_5_GHZ_WITH_DFS  = 6;  /* 5 GHz band with DFS channels */
-    /** Both 2.4 GHz band and 5 GHz band; no DFS channels */
-    public static final int WIFI_BAND_BOTH = 3;             /* both bands without DFS channels */
+    public static final int WIFI_BAND_5_GHZ_WITH_DFS  = 6;
     /** Both 2.4 GHz band and 5 GHz band; with DFS channels */
-    public static final int WIFI_BAND_BOTH_WITH_DFS = 7;    /* both bands with DFS channels */
+    public static final int WIFI_BAND_BOTH_WITH_DFS = 7;
     /**
      * Max band value
      * @hide
@@ -78,9 +93,9 @@
     public static final int WIFI_BAND_MAX = 8;
 
     /** Minimum supported scanning period */
-    public static final int MIN_SCAN_PERIOD_MS = 1000;      /* minimum supported period */
+    public static final int MIN_SCAN_PERIOD_MS = 1000;
     /** Maximum supported scanning period */
-    public static final int MAX_SCAN_PERIOD_MS = 1024000;   /* maximum supported period */
+    public static final int MAX_SCAN_PERIOD_MS = 1024000;
 
     /** No Error */
     public static final int REASON_SUCCEEDED = 0;
@@ -109,16 +124,23 @@
     }
 
     /**
-     * gives you all the possible channels; channel is specified as an
-     * integer with frequency in MHz i.e. channel 1 is 2412
+     * Returns a list of all the possible channels for the given band(s).
+     *
+     * @param band one of the WifiScanner#WIFI_BAND_* constants, e.g. {@link #WIFI_BAND_24_GHZ}
+     * @return a list of all the frequencies, in MHz, for the given band(s) e.g. channel 1 is
+     * 2412, or null if an error occurred.
+     *
      * @hide
      */
-    public List<Integer> getAvailableChannels(int band) {
+    @SystemApi
+    @NonNull
+    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
+    public List<Integer> getAvailableChannels(@WifiBand int band) {
         try {
-            Bundle bundle =  mService.getAvailableChannels(band);
+            Bundle bundle = mService.getAvailableChannels(band, mContext.getOpPackageName());
             return bundle.getIntegerArrayList(GET_AVAILABLE_CHANNELS_EXTRA);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -321,7 +343,7 @@
         }
 
         /** Implement the Parcelable interface {@hide} */
-        public static final @android.annotation.NonNull Creator<ScanSettings> CREATOR =
+        public static final @NonNull Creator<ScanSettings> CREATOR =
                 new Creator<ScanSettings>() {
                     public ScanSettings createFromParcel(Parcel in) {
                         ScanSettings settings = new ScanSettings();
@@ -469,7 +491,7 @@
         }
 
         /** Implement the Parcelable interface {@hide} */
-        public static final @android.annotation.NonNull Creator<ScanData> CREATOR =
+        public static final @NonNull Creator<ScanData> CREATOR =
                 new Creator<ScanData>() {
                     public ScanData createFromParcel(Parcel in) {
                         int id = in.readInt();
@@ -518,7 +540,7 @@
         }
 
         /** Implement the Parcelable interface {@hide} */
-        public static final @android.annotation.NonNull Creator<ParcelableScanData> CREATOR =
+        public static final @NonNull Creator<ParcelableScanData> CREATOR =
                 new Creator<ParcelableScanData>() {
                     public ParcelableScanData createFromParcel(Parcel in) {
                         int n = in.readInt();
@@ -566,7 +588,7 @@
         }
 
         /** Implement the Parcelable interface {@hide} */
-        public static final @android.annotation.NonNull Creator<ParcelableScanResults> CREATOR =
+        public static final @NonNull Creator<ParcelableScanResults> CREATOR =
                 new Creator<ParcelableScanResults>() {
                     public ParcelableScanResults createFromParcel(Parcel in) {
                         int n = in.readInt();
@@ -697,7 +719,7 @@
         }
 
         /** Implement the Parcelable interface {@hide} */
-        public static final @android.annotation.NonNull Creator<PnoSettings> CREATOR =
+        public static final @NonNull Creator<PnoSettings> CREATOR =
                 new Creator<PnoSettings>() {
                     public PnoSettings createFromParcel(Parcel in) {
                         PnoSettings settings = new PnoSettings();
@@ -1045,7 +1067,7 @@
         }
 
         /** Implement the Parcelable interface {@hide} */
-        public static final @android.annotation.NonNull Creator<WifiChangeSettings> CREATOR =
+        public static final @NonNull Creator<WifiChangeSettings> CREATOR =
                 new Creator<WifiChangeSettings>() {
                     public WifiChangeSettings createFromParcel(Parcel in) {
                         return new WifiChangeSettings();
@@ -1156,7 +1178,7 @@
         }
 
         /** Implement the Parcelable interface {@hide} */
-        public static final @android.annotation.NonNull Creator<HotlistSettings> CREATOR =
+        public static final @NonNull Creator<HotlistSettings> CREATOR =
                 new Creator<HotlistSettings>() {
                     public HotlistSettings createFromParcel(Parcel in) {
                         HotlistSettings settings = new HotlistSettings();
@@ -1389,7 +1411,7 @@
         }
 
         /** Implement the Parcelable interface {@hide} */
-        public static final @android.annotation.NonNull Creator<OperationResult> CREATOR =
+        public static final @NonNull Creator<OperationResult> CREATOR =
                 new Creator<OperationResult>() {
                     public OperationResult createFromParcel(Parcel in) {
                         int reason = in.readInt();
diff --git a/wifi/java/android/net/wifi/hotspot2/ConfigParser.java b/wifi/java/android/net/wifi/hotspot2/ConfigParser.java
index e8e8731..bb01365 100644
--- a/wifi/java/android/net/wifi/hotspot2/ConfigParser.java
+++ b/wifi/java/android/net/wifi/hotspot2/ConfigParser.java
@@ -182,6 +182,12 @@
             throw new IOException("Passpoint profile missing credential");
         }
 
+        // Don't allow the installer to make changes to the update identifier. This is an
+        // indicator of an R2 (or newer) network.
+        if (config.getUpdateIdentifier() != Integer.MIN_VALUE) {
+            config.setUpdateIdentifier(Integer.MIN_VALUE);
+        }
+
         // Parse CA (Certificate Authority) certificate.
         byte[] caCertData = mimeParts.get(TYPE_CA_CERT);
         if (caCertData != null) {
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 557b7c9..5befb54 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -24,6 +24,7 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -65,6 +66,7 @@
      * Configurations under HomeSp subtree.
      */
     private HomeSp mHomeSp = null;
+
     /**
      * Set the Home SP (Service Provider) information.
      *
@@ -248,7 +250,10 @@
         mSubscriptionExpirationTimeInMillis = subscriptionExpirationTimeInMillis;
     }
     /**
-     * @hide
+     *  Utility method to get the time this subscription will expire. It is in the format of number
+     *  of milliseconds since January 1, 1970, 00:00:00 GMT.
+     *
+     *  @return The time this subscription will expire, or Long.MIN_VALUE to indicate unset value
      */
     public long getSubscriptionExpirationTimeInMillis() {
         return mSubscriptionExpirationTimeInMillis;
@@ -394,6 +399,30 @@
     }
 
     /**
+     * The carrier ID identifies the operator who provides this network configuration.
+     *    see {@link TelephonyManager#getSimCarrierId()}
+     */
+    private int mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
+
+    /**
+     * Set the carrier ID associated with current configuration.
+     * @param carrierId {@code mCarrierId}
+     * @hide
+     */
+    public void setCarrierId(int carrierId) {
+        this.mCarrierId = carrierId;
+    }
+
+    /**
+     * Get the carrier ID associated with current configuration.
+     * @return {@code mCarrierId}
+     * @hide
+     */
+    public int getCarrierId() {
+        return mCarrierId;
+    }
+
+    /**
      * Constructor for creating PasspointConfiguration with default values.
      */
     public PasspointConfiguration() {}
@@ -434,6 +463,7 @@
         mUsageLimitUsageTimePeriodInMinutes = source.mUsageLimitUsageTimePeriodInMinutes;
         mServiceFriendlyNames = source.mServiceFriendlyNames;
         mAaaServerTrustedNames = source.mAaaServerTrustedNames;
+        mCarrierId = source.mCarrierId;
     }
 
     @Override
@@ -462,6 +492,7 @@
         bundle.putSerializable("serviceFriendlyNames",
                 (HashMap<String, String>) mServiceFriendlyNames);
         dest.writeBundle(bundle);
+        dest.writeInt(mCarrierId);
     }
 
     @Override
@@ -491,6 +522,7 @@
                 && mUsageLimitStartTimeInMillis == that.mUsageLimitStartTimeInMillis
                 && mUsageLimitDataLimit == that.mUsageLimitDataLimit
                 && mUsageLimitTimeLimitInMinutes == that.mUsageLimitTimeLimitInMinutes
+                && mCarrierId == that.mCarrierId
                 && (mServiceFriendlyNames == null ? that.mServiceFriendlyNames == null
                 : mServiceFriendlyNames.equals(that.mServiceFriendlyNames));
     }
@@ -501,7 +533,7 @@
                 mUpdateIdentifier, mCredentialPriority, mSubscriptionCreationTimeInMillis,
                 mSubscriptionExpirationTimeInMillis, mUsageLimitUsageTimePeriodInMinutes,
                 mUsageLimitStartTimeInMillis, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes,
-                mServiceFriendlyNames);
+                mServiceFriendlyNames, mCarrierId);
     }
 
     @Override
@@ -521,6 +553,8 @@
                 .append("\n");
         builder.append("UsageLimitDataLimit: ").append(mUsageLimitDataLimit).append("\n");
         builder.append("UsageLimitTimeLimit: ").append(mUsageLimitTimeLimitInMinutes).append("\n");
+        builder.append("Provisioned by a subscription server: ")
+                .append(isOsuProvisioned() ? "Yes" : "No").append("\n");
         if (mHomeSp != null) {
             builder.append("HomeSP Begin ---\n");
             builder.append(mHomeSp);
@@ -552,6 +586,7 @@
         if (mServiceFriendlyNames != null) {
             builder.append("ServiceFriendlyNames: ").append(mServiceFriendlyNames);
         }
+        builder.append("CarrierId:" + mCarrierId);
         return builder.toString();
     }
 
@@ -656,6 +691,7 @@
                 Map<String, String> friendlyNamesMap = (HashMap) bundle.getSerializable(
                         "serviceFriendlyNames");
                 config.setServiceFriendlyNames(friendlyNamesMap);
+                config.mCarrierId = in.readInt();
                 return config;
             }
 
@@ -728,4 +764,14 @@
         }
         return true;
     }
+
+    /**
+     * Indicates if the Passpoint Configuration was provisioned by a subscription (OSU) server,
+     * which means that it's an R2 (or R3) profile.
+     *
+     * @return true if the Passpoint Configuration was provisioned by a subscription server.
+     */
+    public boolean isOsuProvisioned() {
+        return getUpdateIdentifier() != Integer.MIN_VALUE;
+    }
 }
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index 94fb5ae..4b7d205 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -32,6 +32,7 @@
 import android.net.wifi.ITxPacketCountListener;
 import android.net.wifi.IWifiManager;
 import android.net.wifi.ScanResult;
+import android.net.wifi.SoftApConfiguration;
 import android.net.wifi.WifiActivityEnergyInfo;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
@@ -168,6 +169,11 @@
     }
 
     @Override
+    public void allowAutojoin(int netId, boolean choice) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public boolean startScan(String packageName) {
         throw new UnsupportedOperationException();
     }
@@ -288,8 +294,15 @@
         throw new UnsupportedOperationException();
     }
 
-    @Override
+    /** @deprecated replaced by newer signature */
+    @Deprecated
     public int startLocalOnlyHotspot(ILocalOnlyHotspotCallback callback, String packageName) {
+        return startLocalOnlyHotspot(callback, packageName, null);
+    }
+
+    @Override
+    public int startLocalOnlyHotspot(ILocalOnlyHotspotCallback callback, String packageName,
+            SoftApConfiguration customConfig) {
         throw new UnsupportedOperationException();
     }
 
diff --git a/wifi/tests/Android.mk b/wifi/tests/Android.mk
index 401b652..3453d6e 100644
--- a/wifi/tests/Android.mk
+++ b/wifi/tests/Android.mk
@@ -49,6 +49,7 @@
     core-test-rules \
     guava \
     mockito-target-minus-junit4 \
+    net-tests-utils \
     frameworks-base-testutils \
     truth-prebuilt \
 
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64
index 56919c2..760c839 100644
--- a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.base64
@@ -12,75 +12,75 @@
 OWtaVTVoYldVK0NpQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFRtRnRaVDVJYjIx
 bFUxQTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEU1
 dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdApaVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNB
-OFZtRnNkV1UrUTJWdWRIVnllU0JJYjNWelpUd3ZWbUZzZFdVK0NpQWdJQ0FnCklDQWdQQzlPYjJS
-bFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrWlJSRTQ4
-TDA1dlpHVk8KWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBtMXBOaTVqYnk1MWF6d3ZWbUZz
-ZFdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0Fn
-SUNBZ1BFNXZaR1ZPWVcxbFBsSnZZVzFwYm1kRGIyNXpiM0owYVhWdFQwazhMMDV2ClpHVk9ZVzFs
-UGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGpFeE1qSXpNeXcwTkRVMU5qWThMMVpoYkhWbFBnb2dJ
-Q0FnSUNBZ0lEd3YKVG05a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0E4VG05a1pUNEtJ
-Q0FnSUNBZ0lDQThUbTlrWlU1aGJXVStRM0psWkdWdQpkR2xoYkR3dlRtOWtaVTVoYldVK0NpQWdJ
-Q0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1VtVmhiRzA4CkwwNXZa
-R1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBuTm9ZV3RsYmk1emRHbHljbVZrTG1OdmJU
-d3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lD
-QWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsVnpaWEp1WVcxbApVR0Z6YzNkdmNtUThMMDV2WkdWT1lX
-MWxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmxUbUZ0ClpU
-NVZjMlZ5Ym1GdFpUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lXeDFaVDVxWVcx
-bGN6d3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4VG05
-a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxCaApjM04zYjNKa1BDOU9iMlJsVG1G
-dFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbGx0T1hWYVJFRjNUbmM5UFR3dlZtRnNkV1Ur
-CkNpQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0Fn
-SUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtWQlVFMWxkR2h2WkR3dlRtOWtaVTVoYldVK0NpQWdJQ0Fn
-SUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0FnSUR4TwpiMlJsVG1GdFpUNUZRVkJV
-ZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnSUNBOFZtRnNkV1UrTWpFOEwxWmhi
-SFZsClBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmxQ
-Z29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRaVDVKYm01bGNrMWxkR2h2WkR3dlRtOWta
-VTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQazFUTFVOSQpRVkF0VmpJOEwxWmhi
-SFZsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0Np
-QWdJQ0FnCklDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BF
-NXZaR1ZPWVcxbFBrUnBaMmwwWVd4RFpYSjAKYVdacFkyRjBaVHd2VG05a1pVNWhiV1UrQ2lBZ0lD
-QWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbApQa05sY25ScFpt
-bGpZWFJsVkhsd1pUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lXeDFaVDU0TlRB
-NWRqTThMMVpoCmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEU1
-dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEowVTBoQk1qVTJSbWx1WjJW
-eWNISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdVKwpNV1l4WmpG
+OFZtRnNkV1UrUlhoaGJYQnNaU0JPWlhSM2IzSnJQQzlXWVd4MVpUNEtJQ0FnCklDQWdJQ0E4TDA1
+dlpHVStDaUFnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStSbEZF
+VGp3dlRtOWsKWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4Vm1Gc2RXVSthRzkwYzNCdmRDNWxlR0Z0
+Y0d4bExtNWxkRHd2Vm1Gc2RXVStDaUFnSUNBZwpJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHhP
+YjJSbFBnb2dJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQbEp2WVcxcGJtZERiMjV6CmIzSjBhWFZ0
+VDBrOEwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBqRXhNakl6TXl3ME5EVTFO
+alk4TDFaaGJIVmwKUGdvZ0lDQWdJQ0FnSUR3dlRtOWtaVDRLSUNBZ0lDQWdQQzlPYjJSbFBnb2dJ
+Q0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0E4VG05awpaVTVoYldVK1EzSmxaR1Z1ZEdsaGJEd3ZU
+bTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrClpVNWhi
+V1UrVW1WaGJHMDhMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbVY0WVcxd2JH
+VXVZMjl0UEM5V1lXeDEKWlQ0S0lDQWdJQ0FnSUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEU1dlpH
+VStDaUFnSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrVlhObApjbTVoYldWUVlYTnpkMjl5WkR3dlRt
+OWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2ClpH
+Vk9ZVzFsUGxWelpYSnVZVzFsUEM5T2IyUmxUbUZ0WlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQRlpoYkhW
+bFBuVnpaWEk4TDFaaGJIVmwKUGdvZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUNB
+Z1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE9iMlJsVG1GdApaVDVRWVhOemQyOXlaRHd2VG05
+a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gxWlQ1alIwWjZZek5rZG1OdFVUMDhMMVpo
+CmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFn
+SUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNUZRVkJOWlhSb2IyUThMMDV2WkdWT1lXMWxQZ29n
+SUNBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZwpJQ0E4VG05a1pVNWhiV1Ur
+UlVGUVZIbHdaVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBqSXhQ
+QzlXCllXeDFaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThU
+bTlrWlQ0S0lDQWdJQ0FnSUNBZ0lDQWcKSUNBOFRtOWtaVTVoYldVK1NXNXVaWEpOWlhSb2IyUThM
+MDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gxWlQ1TgpVeTFEU0VGUUxWWXlQ
+QzlXWVd4MVpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2Iy
+UmxQZ29nCklDQWdJQ0FnSUR3dlRtOWtaVDRLSUNBZ0lDQWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lD
+QWdJRHhPYjJSbFRtRnRaVDVFYVdkcGRHRnMKUTJWeWRHbG1hV05oZEdVOEwwNXZaR1ZPWVcxbFBn
+b2dJQ0FnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbApUbUZ0WlQ1RFpY
+SjBhV1pwWTJGMFpWUjVjR1U4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
+K2VEVXdPWFl6ClBDOVdZV3gxWlQ0S0lDQWdJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJQ0FnSUNB
+Z0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ0lDQTgKVG05a1pVNWhiV1UrUTJWeWRGTklRVEkxTmta
+cGJtZGxjbkJ5YVc1MFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaApiSFZsUGpG
 bU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZt
-TVdZeFpqRm1NV1l4ClpqRm1NV1l4Wmp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNBOEwwNXZaR1Ur
-Q2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWcKSUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0Fn
-UEU1dlpHVk9ZVzFsUGxOSlRUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4VG05awpaVDRL
-SUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrbE5VMGs4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJ
-Q0FnSUNBZ0lDQThWbUZzCmRXVSthVzF6YVR3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNBOEwwNXZa
-R1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWcKSUNBZ0lDQWdQRTV2WkdWT1lXMWxQ
-a1ZCVUZSNWNHVThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBOFZtRnNkV1UrTWpROApM
-MVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lD
-QWdJQ0FnUEM5T2IyUmxQZ29nCklDQWdQQzlPYjJSbFBnb2dJRHd2VG05a1pUNEtQQzlOWjIxMFZI
-SmxaVDRLCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94LXg1MDktY2Et
-Y2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFDUlVkSlRpQkRS
-VkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtRVWxNYkVaa2Qz
-cE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5UbFlLUWtGTlZF
-SXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpUazFxV1hkTlZF
-RTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5VVEJGZUUxSlNV
-Skpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMwTkJVVVZCQ25w
-dVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZYTldkVzFFWWxs
-SWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01TdHZSMWhhZGto
-M2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJVRkRaV1pXYW1v
-d2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJoU1FqZzFNVEpR
-UWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdKck1IVjVhM1Jr
-WW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtzM2FFUTRjRkIy
-WmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxhCmFYQllOREY0
-UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVXTTJreGRIRXdO
-R3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZHU1hkWU5IWnpP
-RUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFFYlVGR1NYZFlO
-SFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJkMFJuCldVUldV
-VkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldVakJVUWtGVmQw
-RjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZMDVCVVVWTVFs
-RkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZDamxIUlZBdmRX
-OW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNYZEpWV00zCmQy
-azNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1EwOTBhWE5rUW5F
-eWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JXMVdUQW94Y1VK
-S2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVFMXVWR3c0ZUVW
-WFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhwaFNFb3hkVlk0
-Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpGS1VDdHNlRllL
-YlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNSa1RrNTJRMWw2
-YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmtsRFFWUkZMUzB0
-TFMwSwotLXtib3VuZGFyeX0tLQo=
+TVdZeFpqRm1NV1l4ClpqRm1NV1l4WmpGbU1XWThMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlP
+YjJSbFBnb2dJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWcKSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0Fn
+SUNBZ0lEeE9iMlJsVG1GdFpUNVRTVTA4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZwpQRTV2
+WkdVK0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFRtRnRaVDVKVFZOSlBDOU9iMlJsVG1GdFpUNEtJ
+Q0FnSUNBZ0lDQWdJQ0FnClBGWmhiSFZsUGpFeU16UTFOaW84TDFaaGJIVmxQZ29nSUNBZ0lDQWdJ
+Q0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVSsKQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE9i
+MlJsVG1GdFpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaApi
+SFZsUGpJelBDOVdZV3gxWlQ0S0lDQWdJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJQ0FnSUNBOEww
+NXZaR1UrQ2lBZ0lDQWdJRHd2ClRtOWtaVDRLSUNBZ0lEd3ZUbTlrWlQ0S0lDQThMMDV2WkdVK0Nq
+d3ZUV2R0ZEZSeVpXVSsKCi0te2JvdW5kYXJ5fQpDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL3gt
+eDUwOS1jYS1jZXJ0CkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IGJhc2U2NAoKTFMwdExTMUNS
+VWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVUkxSRU5EUVdoRFowRjNTVUpCWjBsS1FV
+bE1iRVprZDNwTQpWblZ5VFVFd1IwTlRjVWRUU1dJelJGRkZRa04zVlVGTlFrbDRSVVJCVDBKblRs
+WUtRa0ZOVkVJd1ZrSlZRMEpFVVZSRmQwaG9ZMDVOClZGbDNUVlJGZVUxVVJURk5SRVV4VjJoalRr
+MXFXWGROVkVFMVRWUkZNVTFFUlRGWGFrRlRUVkpCZHdwRVoxbEVWbEZSUkVWM1pFWlIKVmtGblVU
+QkZlRTFKU1VKSmFrRk9RbWRyY1docmFVYzVkekJDUVZGRlJrRkJUME5CVVRoQlRVbEpRa05uUzBO
+QlVVVkJDbnB1UVZCVgplakkyVFhOaFpUUjNjelF6WTNwU05ERXZTakpSZEhKVFNWcFZTMjFXVlhO
+V2RXMUVZbGxJY2xCT2RsUllTMU5OV0VGalpYZFBVa1JSCldWZ0tVbkYyU0had2JqaERjMk5DTVN0
+dlIxaGFka2gzZUdvMGVsWXdWMHR2U3pKNlpWaHJZWFV6ZG1ONWJETklTVXQxY0VwbWNUSlUKUlVG
+RFpXWldhbW93ZEFwS1Z5dFlNelZRUjFkd09TOUlOWHBKVlU1V1RsWnFVemRWYlhNNE5FbDJTMmhT
+UWpnMU1USlFRamxWZVVoaApaMWhaVmxnMVIxZHdRV05XY0hsbWNteFNDa1pKT1ZGa2FHZ3JVR0py
+TUhWNWEzUmtZbVl2UTJSbVowaFBiMlZpY2xSMGQxSnNhazB3CmIwUjBXQ3N5UTNZMmFqQjNRa3Mz
+YUVRNGNGQjJaakVyZFhrS1IzcGplbWxuUVZVdk5FdDNOMlZhY1hsa1pqbENLelZTZFhCU0swbGEK
+YVhCWU5ERjRSV2xKY2t0U2QzRnBOVEUzVjFkNldHTnFZVWN5WTA1aVpqUTFNUXA0Y0VnMVVHNVdN
+Mmt4ZEhFd05HcE5SMUZWZWtaMwpTVVJCVVVGQ2J6UkhRVTFJTkhkSVVWbEVWbEl3VDBKQ1dVVkdT
+WGRZTkhaek9FSnBRbU5UWTI5a0NqVnViMXBJVWswNFJUUXJhVTFGClNVZEJNVlZrU1hkUk4wMUVi
+VUZHU1hkWU5IWnpPRUpwUW1OVFkyOWtOVzV2V2toU1RUaEZOQ3RwYjFKaGEwWkVRVk1LVFZKQmQw
+Um4KV1VSV1VWRkVSWGRrUmxGV1FXZFJNRVY0WjJkclFXZDFWVll6UkUxMFZ6WnpkMFJCV1VSV1Vq
+QlVRa0ZWZDBGM1JVSXZla0ZNUW1kTwpWZ3BJVVRoRlFrRk5RMEZSV1hkRVVWbEtTMjlhU1doMlkw
+NUJVVVZNUWxGQlJHZG5SVUpCUm1aUmNVOVVRVGRTZGpkTEsyeDFVVGR3CmJtRnpORUpaZDBoRkNq
+bEhSVkF2ZFc5b2RqWkxUM2t3VkVkUlJtSnlVbFJxUm05TVZrNUNPVUphTVhsdFRVUmFNQzlVU1hk
+SlZXTTMKZDJrM1lUaDBOVzFGY1ZsSU1UVXpkMWNLWVZkdmIybFRhbmxNVEdoMVNUUnpUbkpPUTA5
+MGFYTmtRbkV5Y2pKTlJsaDBObWd3YlVGUgpXVTlRZGpoU09FczNMMlpuVTNoSFJuRjZhSGxPYlcx
+V1RBb3hjVUpLYkdSNE16UlRjSGR6VkVGTVVWWlFZalJvUjNkS2VscG1jakZRClkzQkZVWGcyZUUx
+dVZHdzRlRVZYV2tVelRYTTVPWFZoVlhoaVVYRkpkMUoxQ2t4blFVOXJUa050V1RKdE9EbFdhSHBo
+U0VveGRWWTQKTlVGa1RTOTBSQ3RaYzIxc2JtNXFkRGxNVWtObGFtSkNhWEJxU1VkcVQxaHlaekZL
+VUN0c2VGWUtiWFZOTkhaSUsxQXZiV3h0ZUhOUQpVSG93WkRZMVlpdEZSMjFLV25CdlRHdFBMM1Jr
+VGs1MlExbDZha3B3VkVWWGNFVnpUelpPVFdoTFdXODlDaTB0TFMwdFJVNUVJRU5GClVsUkpSa2xE
+UVZSRkxTMHRMUzBLCi0te2JvdW5kYXJ5fS0tCg==
\ No newline at end of file
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf
index a44b542..5b4e4cb 100644
--- a/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithCACert.conf
@@ -13,38 +13,38 @@
 ICAgICA8L1R5cGU+CiAgICA8L1JUUHJvcGVydGllcz4KICAgIDxOb2RlPgogICAgICA8Tm9kZU5h
 bWU+aTAwMTwvTm9kZU5hbWU+CiAgICAgIDxOb2RlPgogICAgICAgIDxOb2RlTmFtZT5Ib21lU1A8
 L05vZGVOYW1lPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPkZyaWVuZGx5TmFt
-ZTwvTm9kZU5hbWU+CiAgICAgICAgICA8VmFsdWU+Q2VudHVyeSBIb3VzZTwvVmFsdWU+CiAgICAg
-ICAgPC9Ob2RlPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPkZRRE48L05vZGVO
-YW1lPgogICAgICAgICAgPFZhbHVlPm1pNi5jby51azwvVmFsdWU+CiAgICAgICAgPC9Ob2RlPgog
-ICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPlJvYW1pbmdDb25zb3J0aXVtT0k8L05v
-ZGVOYW1lPgogICAgICAgICAgPFZhbHVlPjExMjIzMyw0NDU1NjY8L1ZhbHVlPgogICAgICAgIDwv
-Tm9kZT4KICAgICAgPC9Ob2RlPgogICAgICA8Tm9kZT4KICAgICAgICA8Tm9kZU5hbWU+Q3JlZGVu
-dGlhbDwvTm9kZU5hbWU+CiAgICAgICAgPE5vZGU+CiAgICAgICAgICA8Tm9kZU5hbWU+UmVhbG08
-L05vZGVOYW1lPgogICAgICAgICAgPFZhbHVlPnNoYWtlbi5zdGlycmVkLmNvbTwvVmFsdWU+CiAg
-ICAgICAgPC9Ob2RlPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPlVzZXJuYW1l
-UGFzc3dvcmQ8L05vZGVOYW1lPgogICAgICAgICAgPE5vZGU+CiAgICAgICAgICAgIDxOb2RlTmFt
-ZT5Vc2VybmFtZTwvTm9kZU5hbWU+CiAgICAgICAgICAgIDxWYWx1ZT5qYW1lczwvVmFsdWU+CiAg
-ICAgICAgICA8L05vZGU+CiAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAgPE5vZGVOYW1lPlBh
-c3N3b3JkPC9Ob2RlTmFtZT4KICAgICAgICAgICAgPFZhbHVlPlltOXVaREF3Tnc9PTwvVmFsdWU+
-CiAgICAgICAgICA8L05vZGU+CiAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAgPE5vZGVOYW1l
-PkVBUE1ldGhvZDwvTm9kZU5hbWU+CiAgICAgICAgICAgIDxOb2RlPgogICAgICAgICAgICAgIDxO
-b2RlTmFtZT5FQVBUeXBlPC9Ob2RlTmFtZT4KICAgICAgICAgICAgICA8VmFsdWU+MjE8L1ZhbHVl
-PgogICAgICAgICAgICA8L05vZGU+CiAgICAgICAgICAgIDxOb2RlPgogICAgICAgICAgICAgIDxO
-b2RlTmFtZT5Jbm5lck1ldGhvZDwvTm9kZU5hbWU+CiAgICAgICAgICAgICAgPFZhbHVlPk1TLUNI
-QVAtVjI8L1ZhbHVlPgogICAgICAgICAgICA8L05vZGU+CiAgICAgICAgICA8L05vZGU+CiAgICAg
-ICAgPC9Ob2RlPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPkRpZ2l0YWxDZXJ0
-aWZpY2F0ZTwvTm9kZU5hbWU+CiAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAgPE5vZGVOYW1l
-PkNlcnRpZmljYXRlVHlwZTwvTm9kZU5hbWU+CiAgICAgICAgICAgIDxWYWx1ZT54NTA5djM8L1Zh
+ZTwvTm9kZU5hbWU+CiAgICAgICAgICA8VmFsdWU+RXhhbXBsZSBOZXR3b3JrPC9WYWx1ZT4KICAg
+ICAgICA8L05vZGU+CiAgICAgICAgPE5vZGU+CiAgICAgICAgICA8Tm9kZU5hbWU+RlFETjwvTm9k
+ZU5hbWU+CiAgICAgICAgICA8VmFsdWU+aG90c3BvdC5leGFtcGxlLm5ldDwvVmFsdWU+CiAgICAg
+ICAgPC9Ob2RlPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPlJvYW1pbmdDb25z
+b3J0aXVtT0k8L05vZGVOYW1lPgogICAgICAgICAgPFZhbHVlPjExMjIzMyw0NDU1NjY8L1ZhbHVl
+PgogICAgICAgIDwvTm9kZT4KICAgICAgPC9Ob2RlPgogICAgICA8Tm9kZT4KICAgICAgICA8Tm9k
+ZU5hbWU+Q3JlZGVudGlhbDwvTm9kZU5hbWU+CiAgICAgICAgPE5vZGU+CiAgICAgICAgICA8Tm9k
+ZU5hbWU+UmVhbG08L05vZGVOYW1lPgogICAgICAgICAgPFZhbHVlPmV4YW1wbGUuY29tPC9WYWx1
+ZT4KICAgICAgICA8L05vZGU+CiAgICAgICAgPE5vZGU+CiAgICAgICAgICA8Tm9kZU5hbWU+VXNl
+cm5hbWVQYXNzd29yZDwvTm9kZU5hbWU+CiAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAgPE5v
+ZGVOYW1lPlVzZXJuYW1lPC9Ob2RlTmFtZT4KICAgICAgICAgICAgPFZhbHVlPnVzZXI8L1ZhbHVl
+PgogICAgICAgICAgPC9Ob2RlPgogICAgICAgICAgPE5vZGU+CiAgICAgICAgICAgIDxOb2RlTmFt
+ZT5QYXNzd29yZDwvTm9kZU5hbWU+CiAgICAgICAgICAgIDxWYWx1ZT5jR0Z6YzNkdmNtUT08L1Zh
 bHVlPgogICAgICAgICAgPC9Ob2RlPgogICAgICAgICAgPE5vZGU+CiAgICAgICAgICAgIDxOb2Rl
-TmFtZT5DZXJ0U0hBMjU2RmluZ2VycHJpbnQ8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFsdWU+
-MWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYx
-ZjFmMWYxZjwvVmFsdWU+CiAgICAgICAgICA8L05vZGU+CiAgICAgICAgPC9Ob2RlPgogICAgICAg
-IDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPlNJTTwvTm9kZU5hbWU+CiAgICAgICAgICA8Tm9k
-ZT4KICAgICAgICAgICAgPE5vZGVOYW1lPklNU0k8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFs
-dWU+aW1zaTwvVmFsdWU+CiAgICAgICAgICA8L05vZGU+CiAgICAgICAgICA8Tm9kZT4KICAgICAg
-ICAgICAgPE5vZGVOYW1lPkVBUFR5cGU8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFsdWU+MjQ8
-L1ZhbHVlPgogICAgICAgICAgPC9Ob2RlPgogICAgICAgIDwvTm9kZT4KICAgICAgPC9Ob2RlPgog
-ICAgPC9Ob2RlPgogIDwvTm9kZT4KPC9NZ210VHJlZT4K
+TmFtZT5FQVBNZXRob2Q8L05vZGVOYW1lPgogICAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAg
+ICA8Tm9kZU5hbWU+RUFQVHlwZTwvTm9kZU5hbWU+CiAgICAgICAgICAgICAgPFZhbHVlPjIxPC9W
+YWx1ZT4KICAgICAgICAgICAgPC9Ob2RlPgogICAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAg
+ICA8Tm9kZU5hbWU+SW5uZXJNZXRob2Q8L05vZGVOYW1lPgogICAgICAgICAgICAgIDxWYWx1ZT5N
+Uy1DSEFQLVYyPC9WYWx1ZT4KICAgICAgICAgICAgPC9Ob2RlPgogICAgICAgICAgPC9Ob2RlPgog
+ICAgICAgIDwvTm9kZT4KICAgICAgICA8Tm9kZT4KICAgICAgICAgIDxOb2RlTmFtZT5EaWdpdGFs
+Q2VydGlmaWNhdGU8L05vZGVOYW1lPgogICAgICAgICAgPE5vZGU+CiAgICAgICAgICAgIDxOb2Rl
+TmFtZT5DZXJ0aWZpY2F0ZVR5cGU8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFsdWU+eDUwOXYz
+PC9WYWx1ZT4KICAgICAgICAgIDwvTm9kZT4KICAgICAgICAgIDxOb2RlPgogICAgICAgICAgICA8
+Tm9kZU5hbWU+Q2VydFNIQTI1NkZpbmdlcnByaW50PC9Ob2RlTmFtZT4KICAgICAgICAgICAgPFZh
+bHVlPjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYx
+ZjFmMWYxZjFmMWY8L1ZhbHVlPgogICAgICAgICAgPC9Ob2RlPgogICAgICAgIDwvTm9kZT4KICAg
+ICAgICA8Tm9kZT4KICAgICAgICAgIDxOb2RlTmFtZT5TSU08L05vZGVOYW1lPgogICAgICAgICAg
+PE5vZGU+CiAgICAgICAgICAgIDxOb2RlTmFtZT5JTVNJPC9Ob2RlTmFtZT4KICAgICAgICAgICAg
+PFZhbHVlPjEyMzQ1Nio8L1ZhbHVlPgogICAgICAgICAgPC9Ob2RlPgogICAgICAgICAgPE5vZGU+
+CiAgICAgICAgICAgIDxOb2RlTmFtZT5FQVBUeXBlPC9Ob2RlTmFtZT4KICAgICAgICAgICAgPFZh
+bHVlPjIzPC9WYWx1ZT4KICAgICAgICAgIDwvTm9kZT4KICAgICAgICA8L05vZGU+CiAgICAgIDwv
+Tm9kZT4KICAgIDwvTm9kZT4KICA8L05vZGU+CjwvTWdtdFRyZWU+
 
 --{boundary}
 Content-Type: application/x-x509-ca-cert
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithInvalidContentType.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithInvalidContentType.base64
index 906bfb3..2775a9f 100644
--- a/wifi/tests/assets/hsr1/HSR1ProfileWithInvalidContentType.base64
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithInvalidContentType.base64
@@ -1,85 +1,86 @@
-Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu
-dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh
-cHBsaWNhdGlvbi9wYXNzcG9pbnQtcHJvZmlsZQpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBi
-YXNlNjQKClBFMW5iWFJVY21WbElIaHRiRzV6UFNKemVXNWpiV3c2Wkcxa1pHWXhMaklpUGdvZ0lE
-eFdaWEpFVkVRK01TNHlQQzlXWlhKRVZFUSsKQ2lBZ1BFNXZaR1UrQ2lBZ0lDQThUbTlrWlU1aGJX
-VStVR1Z5VUhKdmRtbGtaWEpUZFdKelkzSnBjSFJwYjI0OEwwNXZaR1ZPWVcxbApQZ29nSUNBZ1BG
-SlVVSEp2Y0dWeWRHbGxjejRLSUNBZ0lDQWdQRlI1Y0dVK0NpQWdJQ0FnSUNBZ1BFUkVSazVoYldV
-K2RYSnVPbmRtCllUcHRienBvYjNSemNHOTBNbVJ2ZERBdGNHVnljSEp2ZG1sa1pYSnpkV0p6WTNK
-cGNIUnBiMjQ2TVM0d1BDOUVSRVpPWVcxbFBnb2cKSUNBZ0lDQThMMVI1Y0dVK0NpQWdJQ0E4TDFK
-VVVISnZjR1Z5ZEdsbGN6NEtJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQThUbTlrWlU1aApiV1UrYVRB
-d01Ud3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxUbUZ0
-WlQ1SWIyMWxVMUE4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0Fn
-SUNBZ1BFNXZaR1ZPWVcxbFBrWnlhV1Z1Wkd4NVRtRnQKWlR3dlRtOWtaVTVoYldVK0NpQWdJQ0Fn
-SUNBZ0lDQThWbUZzZFdVK1EyVnVkSFZ5ZVNCSWIzVnpaVHd2Vm1Gc2RXVStDaUFnSUNBZwpJQ0Fn
-UEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQ
-a1pSUkU0OEwwNXZaR1ZPCllXMWxQZ29nSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbTFwTmk1amJ5NTFh
-end2Vm1Gc2RXVStDaUFnSUNBZ0lDQWdQQzlPYjJSbFBnb2cKSUNBZ0lDQWdJRHhPYjJSbFBnb2dJ
-Q0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQbEp2WVcxcGJtZERiMjV6YjNKMGFYVnRUMGs4TDA1dgpa
-R1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBqRXhNakl6TXl3ME5EVTFOalk4TDFaaGJI
-VmxQZ29nSUNBZ0lDQWdJRHd2ClRtOWtaVDRLSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBOFRt
-OWtaVDRLSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrUTNKbFpHVnUKZEdsaGJEd3ZUbTlrWlU1aGJX
-VStDaUFnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStVbVZoYkcw
-OApMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbk5vWVd0bGJpNXpkR2x5Y21W
-a0xtTnZiVHd2Vm1Gc2RXVStDaUFnCklDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJS
-bFBnb2dJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQbFZ6WlhKdVlXMWwKVUdGemMzZHZjbVE4TDA1
-dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE9iMlJs
-VG1GdApaVDVWYzJWeWJtRnRaVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gx
-WlQ1cVlXMWxjend2Vm1Gc2RXVStDaUFnCklDQWdJQ0FnSUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0Fn
-SUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsQmgKYzNOM2IzSmtQQzlP
-YjJSbFRtRnRaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGxsdE9YVmFSRUYzVG5jOVBUd3ZW
-bUZzZFdVKwpDaUFnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4VG05a1pUNEtJ
-Q0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsClBrVkJVRTFsZEdodlpEd3ZUbTlrWlU1aGJXVStD
-aUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRa
-VDVGUVZCVWVYQmxQQzlPYjJSbFRtRnRaVDRLSUNBZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdVK01q
-RThMMVpoYkhWbApQZ29nSUNBZ0lDQWdJQ0FnSUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lE
-eE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ0lDQWdJRHhPCmIyUmxUbUZ0WlQ1SmJtNWxjazFsZEdodlpE
-d3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGsxVExVTkkKUVZBdFZq
-SThMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4TDA1
-dlpHVStDaUFnSUNBZwpJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNB
-Z0lDQWdQRTV2WkdWT1lXMWxQa1JwWjJsMFlXeERaWEowCmFXWnBZMkYwWlR3dlRtOWtaVTVoYldV
-K0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtO
-bGNuUnBabWxqWVhSbFZIbHdaVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gx
-WlQ1NE5UQTVkak04TDFaaApiSFZsUGdvZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0Fn
-SUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE9iMlJsClRtRnRaVDVEWlhKMFUwaEJNalUy
-Um1sdVoyVnlVSEpwYm5ROEwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4Vm1Gc2RXVSsK
-TVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1N
-V1l4WmpGbU1XWXhaakZtTVdZeApaakZtTVdZeFpqd3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ0lDQThM
-MDV2WkdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnCklEeE9iMlJsUGdvZ0lDQWdJ
-Q0FnSUNBZ1BFNXZaR1ZPWVcxbFBsTkpUVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBOFRt
-OWsKWlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQa2xOVTBrOEwwNXZaR1ZPWVcxbFBn
-b2dJQ0FnSUNBZ0lDQWdJQ0E4Vm1GcwpkV1UrYVcxemFUd3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ0lD
-QThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnCklDQWdJQ0FnUEU1dlpH
-Vk9ZVzFsUGtWQlVGUjVjR1U4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
-K01qUTgKTDFaaGJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHd2VG05
-a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnUEM5T2IyUmxQZ29nSUR3dlRtOWtaVDRLUEM5
-TloyMTBWSEpsWlQ0SwoKLS17Ym91bmRhcnl9CkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24veC14
-NTA5LWNhLWNlcnQKQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgpMUzB0TFMxQ1JV
-ZEpUaUJEUlZKVVNVWkpRMEZVUlMwdExTMHRDazFKU1VSTFJFTkRRV2hEWjBGM1NVSkJaMGxLUVVs
-TWJFWmtkM3BNClZuVnlUVUV3UjBOVGNVZFRTV0l6UkZGRlFrTjNWVUZOUWtsNFJVUkJUMEpuVGxZ
-S1FrRk5WRUl3VmtKVlEwSkVVVlJGZDBob1kwNU4KVkZsM1RWUkZlVTFVUlRGTlJFVXhWMmhqVGsx
-cVdYZE5WRUUxVFZSRk1VMUVSVEZYYWtGVFRWSkJkd3BFWjFsRVZsRlJSRVYzWkVaUgpWa0ZuVVRC
-RmVFMUpTVUpKYWtGT1FtZHJjV2hyYVVjNWR6QkNRVkZGUmtGQlQwTkJVVGhCVFVsSlFrTm5TME5C
-VVVWQkNucHVRVkJWCmVqSTJUWE5oWlRSM2N6UXpZM3BTTkRFdlNqSlJkSEpUU1ZwVlMyMVdWWE5X
-ZFcxRVlsbEljbEJPZGxSWVMxTk5XRUZqWlhkUFVrUlIKV1ZnS1VuRjJTSFp3YmpoRGMyTkNNU3R2
-UjFoYWRraDNlR28wZWxZd1YwdHZTeko2WlZocllYVXpkbU41YkROSVNVdDFjRXBtY1RKVQpSVUZE
-WldaV2Ftb3dkQXBLVnl0WU16VlFSMWR3T1M5SU5YcEpWVTVXVGxacVV6ZFZiWE00TkVsMlMyaFNR
-amcxTVRKUVFqbFZlVWhoCloxaFpWbGcxUjFkd1FXTldjSGxtY214U0NrWkpPVkZrYUdnclVHSnJN
-SFY1YTNSa1ltWXZRMlJtWjBoUGIyVmljbFIwZDFKc2FrMHcKYjBSMFdDc3lRM1kyYWpCM1FrczNh
-RVE0Y0ZCMlpqRXJkWGtLUjNwamVtbG5RVlV2TkV0M04yVmFjWGxrWmpsQ0t6VlNkWEJTSzBsYQph
-WEJZTkRGNFJXbEpja3RTZDNGcE5URTNWMWQ2V0dOcVlVY3lZMDVpWmpRMU1RcDRjRWcxVUc1V00y
-a3hkSEV3TkdwTlIxRlZla1ozClNVUkJVVUZDYnpSSFFVMUlOSGRJVVZsRVZsSXdUMEpDV1VWR1NY
-ZFlOSFp6T0VKcFFtTlRZMjlrQ2pWdWIxcElVazA0UlRRcmFVMUYKU1VkQk1WVmtTWGRSTjAxRWJV
-RkdTWGRZTkhaek9FSnBRbU5UWTI5a05XNXZXa2hTVFRoRk5DdHBiMUpoYTBaRVFWTUtUVkpCZDBS
-bgpXVVJXVVZGRVJYZGtSbEZXUVdkUk1FVjRaMmRyUVdkMVZWWXpSRTEwVnpaemQwUkJXVVJXVWpC
-VVFrRlZkMEYzUlVJdmVrRk1RbWRPClZncElVVGhGUWtGTlEwRlJXWGRFVVZsS1MyOWFTV2gyWTA1
-QlVVVk1RbEZCUkdkblJVSkJSbVpSY1U5VVFUZFNkamRMSzJ4MVVUZHcKYm1Gek5FSlpkMGhGQ2ps
-SFJWQXZkVzlvZGpaTFQza3dWRWRSUm1KeVVsUnFSbTlNVms1Q09VSmFNWGx0VFVSYU1DOVVTWGRK
-VldNMwpkMmszWVRoME5XMUZjVmxJTVRVemQxY0tZVmR2YjJsVGFubE1UR2gxU1RSelRuSk9RMDkw
-YVhOa1FuRXljakpOUmxoME5tZ3diVUZSCldVOVFkamhTT0VzM0wyWm5VM2hIUm5GNmFIbE9iVzFX
-VEFveGNVSktiR1I0TXpSVGNIZHpWRUZNVVZaUVlqUm9SM2RLZWxwbWNqRlEKWTNCRlVYZzJlRTF1
-Vkd3NGVFVlhXa1V6VFhNNU9YVmhWWGhpVVhGSmQxSjFDa3huUVU5clRrTnRXVEp0T0RsV2FIcGhT
-RW94ZFZZNApOVUZrVFM5MFJDdFpjMjFzYm01cWREbE1Va05sYW1KQ2FYQnFTVWRxVDFoeVp6RktV
-Q3RzZUZZS2JYVk5OSFpJSzFBdmJXeHRlSE5RClVIb3daRFkxWWl0RlIyMUtXbkJ2VEd0UEwzUmtU
-azUyUTFsNmFrcHdWRVZYY0VWelR6Wk9UV2hMV1c4OUNpMHRMUzB0UlU1RUlFTkYKVWxSSlJrbERR
-VlJGTFMwdExTMEsKLS17Ym91bmRhcnl9LS0K
+TUlNRS1WZXJzaW9uOiAxLjAKQ29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5
+PXtib3VuZGFyeX07IGNoYXJzZXQ9VVRGLTgKQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogYmFz
+ZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi9wYXNzcG9pbnQtcHJv
+ZmlsZTsgY2hhcnNldD1VVEYtOApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKClBF
+MW5iWFJVY21WbElIaHRiRzV6UFNKemVXNWpiV3c2Wkcxa1pHWXhMaklpUGdvZ0lEeFdaWEpFVkVR
+K01TNHlQQzlXWlhKRVZFUSsKQ2lBZ1BFNXZaR1UrQ2lBZ0lDQThUbTlrWlU1aGJXVStVR1Z5VUhK
+dmRtbGtaWEpUZFdKelkzSnBjSFJwYjI0OEwwNXZaR1ZPWVcxbApQZ29nSUNBZ1BGSlVVSEp2Y0dW
+eWRHbGxjejRLSUNBZ0lDQWdQRlI1Y0dVK0NpQWdJQ0FnSUNBZ1BFUkVSazVoYldVK2RYSnVPbmRt
+CllUcHRienBvYjNSemNHOTBNbVJ2ZERBdGNHVnljSEp2ZG1sa1pYSnpkV0p6WTNKcGNIUnBiMjQ2
+TVM0d1BDOUVSRVpPWVcxbFBnb2cKSUNBZ0lDQThMMVI1Y0dVK0NpQWdJQ0E4TDFKVVVISnZjR1Z5
+ZEdsbGN6NEtJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQThUbTlrWlU1aApiV1UrYVRBd01Ud3ZUbTlr
+WlU1aGJXVStDaUFnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxUbUZ0WlQ1SWIyMWxV
+MUE4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZa
+R1ZPWVcxbFBrWnlhV1Z1Wkd4NVRtRnQKWlR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQThW
+bUZzZFdVK1JYaGhiWEJzWlNCT1pYUjNiM0pyUEM5V1lXeDFaVDRLSUNBZwpJQ0FnSUNBOEwwNXZa
+R1UrQ2lBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrUmxGRVRq
+d3ZUbTlrClpVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBOFZtRnNkV1UrYUc5MGMzQnZkQzVsZUdGdGNH
+eGxMbTVsZER3dlZtRnNkV1UrQ2lBZ0lDQWcKSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUR4T2Iy
+UmxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxKdllXMXBibWREYjI1egpiM0owYVhWdFQw
+azhMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQakV4TWpJek15dzBORFUxTmpZ
+OEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNB
+Z0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNBOFRtOWsKWlU1aGJXVStRM0psWkdWdWRHbGhiRHd2VG05
+a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4VG05awpaVTVoYldV
+K1VtVmhiRzA4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUG1WNFlXMXdiR1V1
+WTI5dFBDOVdZV3gxClpUNEtJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ1BFNXZaR1Ur
+Q2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1ZYTmwKY201aGJXVlFZWE56ZDI5eVpEd3ZUbTlr
+WlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dgpaR1ZP
+WVcxbFBsVnpaWEp1WVcxbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQ
+blZ6WlhJOEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdQ
+RTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFRtRnQKWlQ1UVlYTnpkMjl5WkR3dlRtOWta
+VTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJRHhXWVd4MVpUNWpSMFo2WXpOa2RtTnRVVDA4TDFaaApi
+SFZsUGdvZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lD
+QWdJQ0FnSUNBZ0lEeE9iMlJsClRtRnRaVDVGUVZCTlpYUm9iMlE4TDA1dlpHVk9ZVzFsUGdvZ0lD
+QWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNBZ0lDQWcKSUNBOFRtOWtaVTVoYldVK1JV
+RlFWSGx3WlR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQakl4UEM5
+VwpZV3gxWlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4VG05
+a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnCklDQThUbTlrWlU1aGJXVStTVzV1WlhKTlpYUm9iMlE4TDA1
+dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQWdJRHhXWVd4MVpUNU4KVXkxRFNFRlFMVll5UEM5
+V1lXeDFaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJs
+UGdvZwpJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0Fn
+SUR4T2IyUmxUbUZ0WlQ1RWFXZHBkR0ZzClEyVnlkR2xtYVdOaGRHVThMMDV2WkdWT1lXMWxQZ29n
+SUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEow
+YVdacFkyRjBaVlI1Y0dVOEwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4Vm1Gc2RXVStl
+RFV3T1hZegpQQzlXWVd4MVpUNEtJQ0FnSUNBZ0lDQWdJRHd2VG05a1pUNEtJQ0FnSUNBZ0lDQWdJ
+RHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4ClRtOWtaVTVoYldVK1EyVnlkRk5JUVRJMU5rWnBi
+bWRsY25CeWFXNTBQQzlPYjJSbFRtRnRaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BGWmgKYkhWbFBqRm1N
+V1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1X
+WXhaakZtTVdZeApaakZtTVdZeFpqRm1NV1k4TDFaaGJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2Iy
+UmxQZ29nSUNBZ0lDQWdJRHd2VG05a1pUNEtJQ0FnCklDQWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lD
+QWdJRHhPYjJSbFRtRnRaVDVUU1UwOEwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWcKUEU1dlpH
+VStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmxUbUZ0WlQ1SlRWTkpQQzlPYjJSbFRtRnRaVDRLSUNB
+Z0lDQWdJQ0FnSUNBZwpQRlpoYkhWbFBqRXlNelExTmlvOEwxWmhiSFZsUGdvZ0lDQWdJQ0FnSUNB
+Z1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1UrCkNpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJS
+bFRtRnRaVDVGUVZCVWVYQmxQQzlPYjJSbFRtRnRaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BGWmgKYkhW
+bFBqSXpQQzlXWVd4MVpUNEtJQ0FnSUNBZ0lDQWdJRHd2VG05a1pUNEtJQ0FnSUNBZ0lDQThMMDV2
+WkdVK0NpQWdJQ0FnSUR3dgpUbTlrWlQ0S0lDQWdJRHd2VG05a1pUNEtJQ0E4TDA1dlpHVStDand2
+VFdkdGRGUnlaV1UrCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94LXg1
+MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFDUlVk
+SlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtRVWxN
+YkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5UbFlL
+UWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpUazFx
+V1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5VVEJG
+ZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMwTkJV
+VVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZYTldk
+VzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01TdHZS
+MWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJVRkRa
+V1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJoU1Fq
+ZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdKck1I
+VjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtzM2FF
+UTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxhCmFY
+QllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVXTTJr
+eGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZHU1hk
+WU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFFYlVG
+R1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJkMFJu
+CldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldVakJV
+UWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZMDVC
+VVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZDamxI
+UlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNYZEpW
+V00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1EwOTBh
+WE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JXMVdU
+QW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVFMXVW
+R3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhwaFNF
+b3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpGS1VD
+dHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNSa1Rr
+NTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmtsRFFW
+UkZMUzB0TFMwSwotLXtib3VuZGFyeX0tLQo=
\ No newline at end of file
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithMissingBoundary.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithMissingBoundary.base64
index 3fa97d1..7023453 100644
--- a/wifi/tests/assets/hsr1/HSR1ProfileWithMissingBoundary.base64
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithMissingBoundary.base64
@@ -1,85 +1,86 @@
-Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu
-dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh
-cHBsaWNhdGlvbi94LXBhc3Nwb2ludC1wcm9maWxlCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6
-IGJhc2U2NAoKUEUxbmJYUlVjbVZsSUhodGJHNXpQU0p6ZVc1amJXdzZaRzFrWkdZeExqSWlQZ29n
-SUR4V1pYSkVWRVErTVM0eVBDOVdaWEpFVkVRKwpDaUFnUEU1dlpHVStDaUFnSUNBOFRtOWtaVTVo
-YldVK1VHVnlVSEp2ZG1sa1pYSlRkV0p6WTNKcGNIUnBiMjQ4TDA1dlpHVk9ZVzFsClBnb2dJQ0Fn
-UEZKVVVISnZjR1Z5ZEdsbGN6NEtJQ0FnSUNBZ1BGUjVjR1UrQ2lBZ0lDQWdJQ0FnUEVSRVJrNWhi
-V1UrZFhKdU9uZG0KWVRwdGJ6cG9iM1J6Y0c5ME1tUnZkREF0Y0dWeWNISnZkbWxrWlhKemRXSnpZ
-M0pwY0hScGIyNDZNUzR3UEM5RVJFWk9ZVzFsUGdvZwpJQ0FnSUNBOEwxUjVjR1UrQ2lBZ0lDQThM
-MUpVVUhKdmNHVnlkR2xsY3o0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoCmJXVSth
-VEF3TVR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFRt
-RnRaVDVJYjIxbFUxQTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lD
-QWdJQ0FnUEU1dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdApaVHd2VG05a1pVNWhiV1UrQ2lBZ0lD
-QWdJQ0FnSUNBOFZtRnNkV1UrUTJWdWRIVnllU0JJYjNWelpUd3ZWbUZzZFdVK0NpQWdJQ0FnCklD
-QWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcx
-bFBrWlJSRTQ4TDA1dlpHVk8KWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBtMXBOaTVqYnk1
-MWF6d3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnSUNBZ0lEeE9iMlJsUGdv
-Z0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsSnZZVzFwYm1kRGIyNXpiM0owYVhWdFQwazhMMDV2
-ClpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGpFeE1qSXpNeXcwTkRVMU5qWThMMVpo
-YkhWbFBnb2dJQ0FnSUNBZ0lEd3YKVG05a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0E4
-VG05a1pUNEtJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStRM0psWkdWdQpkR2xoYkR3dlRtOWtaVTVo
-YldVK0NpQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1VtVmhi
-RzA4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBuTm9ZV3RsYmk1emRHbHlj
-bVZrTG1OdmJUd3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9i
-MlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsVnpaWEp1WVcxbApVR0Z6YzNkdmNtUThM
-MDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2Iy
-UmxUbUZ0ClpUNVZjMlZ5Ym1GdFpUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
-eDFaVDVxWVcxbGN6d3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lD
-QWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxCaApjM04zYjNKa1BD
-OU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbGx0T1hWYVJFRjNUbmM5UFR3
-dlZtRnNkV1UrCkNpQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0
-S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtWQlVFMWxkR2h2WkR3dlRtOWtaVTVoYldV
-K0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0FnSUR4TwpiMlJsVG1G
-dFpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnSUNBOFZtRnNkV1Ur
-TWpFOEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0Fn
-SUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRaVDVKYm01bGNrMWxkR2h2
-WkR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQazFUTFVOSQpRVkF0
-VmpJOEwxWmhiSFZsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThM
-MDV2WkdVK0NpQWdJQ0FnCklDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJ
-Q0FnSUNBZ1BFNXZaR1ZPWVcxbFBrUnBaMmwwWVd4RFpYSjAKYVdacFkyRjBaVHd2VG05a1pVNWhi
-V1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbApQ
-a05sY25ScFptbGpZWFJsVkhsd1pUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
-eDFaVDU0TlRBNWRqTThMMVpoCmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lD
-QWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEowVTBoQk1q
-VTJSbWx1WjJWeVVISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
-KwpNV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpG
-bU1XWXhaakZtTVdZeFpqRm1NV1l4ClpqRm1NV1l4Wmp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNB
-OEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWcKSUR4T2IyUmxQZ29nSUNB
-Z0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxOSlRUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4
-VG05awpaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrbE5VMGs4TDA1dlpHVk9ZVzFs
-UGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzCmRXVSthVzF6YVR3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0Fn
-SUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWcKSUNBZ0lDQWdQRTV2
-WkdWT1lXMWxQa1ZCVUZSNWNHVThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBOFZtRnNk
-V1UrTWpROApMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEd3ZU
-bTlrWlQ0S0lDQWdJQ0FnUEM5T2IyUmxQZ29nCklDQWdQQzlPYjJSbFBnb2dJRHd2VG05a1pUNEtQ
-QzlOWjIxMFZISmxaVDRLCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94
-LXg1MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFD
-UlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtR
-VWxNYkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5U
-bFlLUWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpU
-azFxV1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5V
-VEJGZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMw
-TkJVVVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZY
-TldkVzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01T
-dHZSMWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJV
-RkRaV1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJo
-U1FqZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdK
-ck1IVjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtz
-M2FFUTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxh
-CmFYQllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVX
-TTJreGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZH
-U1hkWU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFF
-YlVGR1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJk
-MFJuCldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldV
-akJVUWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZ
-MDVCVVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZD
-amxIUlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNY
-ZEpWV00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1Ew
-OTBhWE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JX
-MVdUQW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVF
-MXVWR3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhw
-aFNFb3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpG
-S1VDdHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNS
-a1RrNTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmts
-RFFWUkZMUzB0TFMwSwo=
+TUlNRS1WZXJzaW9uOiAxLjAKQ29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5
+PXtib3VuZGFyeX07IGNoYXJzZXQ9VVRGLTgKQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogYmFz
+ZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94LXBhc3Nwb2ludC1w
+cm9maWxlOyBjaGFyc2V0PVVURi04CkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IGJhc2U2NAoK
+UEUxbmJYUlVjbVZsSUhodGJHNXpQU0p6ZVc1amJXdzZaRzFrWkdZeExqSWlQZ29nSUR4V1pYSkVW
+RVErTVM0eVBDOVdaWEpFVkVRKwpDaUFnUEU1dlpHVStDaUFnSUNBOFRtOWtaVTVoYldVK1VHVnlV
+SEp2ZG1sa1pYSlRkV0p6WTNKcGNIUnBiMjQ4TDA1dlpHVk9ZVzFsClBnb2dJQ0FnUEZKVVVISnZj
+R1Z5ZEdsbGN6NEtJQ0FnSUNBZ1BGUjVjR1UrQ2lBZ0lDQWdJQ0FnUEVSRVJrNWhiV1UrZFhKdU9u
+ZG0KWVRwdGJ6cG9iM1J6Y0c5ME1tUnZkREF0Y0dWeWNISnZkbWxrWlhKemRXSnpZM0pwY0hScGIy
+NDZNUzR3UEM5RVJFWk9ZVzFsUGdvZwpJQ0FnSUNBOEwxUjVjR1UrQ2lBZ0lDQThMMUpVVUhKdmNH
+VnlkR2xsY3o0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoCmJXVSthVEF3TVR3dlRt
+OWtaVTVoYldVK0NpQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFRtRnRaVDVJYjIx
+bFUxQTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEU1
+dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdApaVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNB
+OFZtRnNkV1UrUlhoaGJYQnNaU0JPWlhSM2IzSnJQQzlXWVd4MVpUNEtJQ0FnCklDQWdJQ0E4TDA1
+dlpHVStDaUFnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStSbEZF
+VGp3dlRtOWsKWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4Vm1Gc2RXVSthRzkwYzNCdmRDNWxlR0Z0
+Y0d4bExtNWxkRHd2Vm1Gc2RXVStDaUFnSUNBZwpJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHhP
+YjJSbFBnb2dJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQbEp2WVcxcGJtZERiMjV6CmIzSjBhWFZ0
+VDBrOEwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBqRXhNakl6TXl3ME5EVTFO
+alk4TDFaaGJIVmwKUGdvZ0lDQWdJQ0FnSUR3dlRtOWtaVDRLSUNBZ0lDQWdQQzlPYjJSbFBnb2dJ
+Q0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0E4VG05awpaVTVoYldVK1EzSmxaR1Z1ZEdsaGJEd3ZU
+bTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrClpVNWhi
+V1UrVW1WaGJHMDhMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbVY0WVcxd2JH
+VXVZMjl0UEM5V1lXeDEKWlQ0S0lDQWdJQ0FnSUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEU1dlpH
+VStDaUFnSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrVlhObApjbTVoYldWUVlYTnpkMjl5WkR3dlRt
+OWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2ClpH
+Vk9ZVzFsUGxWelpYSnVZVzFsUEM5T2IyUmxUbUZ0WlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQRlpoYkhW
+bFBuVnpaWEk4TDFaaGJIVmwKUGdvZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUNB
+Z1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE9iMlJsVG1GdApaVDVRWVhOemQyOXlaRHd2VG05
+a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gxWlQ1alIwWjZZek5rZG1OdFVUMDhMMVpo
+CmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFn
+SUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNUZRVkJOWlhSb2IyUThMMDV2WkdWT1lXMWxQZ29n
+SUNBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZwpJQ0E4VG05a1pVNWhiV1Ur
+UlVGUVZIbHdaVHd2VG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBqSXhQ
+QzlXCllXeDFaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThU
+bTlrWlQ0S0lDQWdJQ0FnSUNBZ0lDQWcKSUNBOFRtOWtaVTVoYldVK1NXNXVaWEpOWlhSb2IyUThM
+MDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gxWlQ1TgpVeTFEU0VGUUxWWXlQ
+QzlXWVd4MVpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2Iy
+UmxQZ29nCklDQWdJQ0FnSUR3dlRtOWtaVDRLSUNBZ0lDQWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lD
+QWdJRHhPYjJSbFRtRnRaVDVFYVdkcGRHRnMKUTJWeWRHbG1hV05oZEdVOEwwNXZaR1ZPWVcxbFBn
+b2dJQ0FnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbApUbUZ0WlQ1RFpY
+SjBhV1pwWTJGMFpWUjVjR1U4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
+K2VEVXdPWFl6ClBDOVdZV3gxWlQ0S0lDQWdJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJQ0FnSUNB
+Z0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ0lDQTgKVG05a1pVNWhiV1UrUTJWeWRGTklRVEkxTmta
+cGJtZGxjbkJ5YVc1MFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaApiSFZsUGpG
+bU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZt
+TVdZeFpqRm1NV1l4ClpqRm1NV1l4WmpGbU1XWThMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlP
+YjJSbFBnb2dJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWcKSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0Fn
+SUNBZ0lEeE9iMlJsVG1GdFpUNVRTVTA4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZwpQRTV2
+WkdVK0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFRtRnRaVDVKVFZOSlBDOU9iMlJsVG1GdFpUNEtJ
+Q0FnSUNBZ0lDQWdJQ0FnClBGWmhiSFZsUGpFeU16UTFOaW84TDFaaGJIVmxQZ29nSUNBZ0lDQWdJ
+Q0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVSsKQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE9i
+MlJsVG1GdFpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaApi
+SFZsUGpJelBDOVdZV3gxWlQ0S0lDQWdJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJQ0FnSUNBOEww
+NXZaR1UrQ2lBZ0lDQWdJRHd2ClRtOWtaVDRLSUNBZ0lEd3ZUbTlrWlQ0S0lDQThMMDV2WkdVK0Nq
+d3ZUV2R0ZEZSeVpXVSsKCi0te2JvdW5kYXJ5fQpDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL3gt
+eDUwOS1jYS1jZXJ0CkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IGJhc2U2NAoKTFMwdExTMUNS
+VWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVUkxSRU5EUVdoRFowRjNTVUpCWjBsS1FV
+bE1iRVprZDNwTQpWblZ5VFVFd1IwTlRjVWRUU1dJelJGRkZRa04zVlVGTlFrbDRSVVJCVDBKblRs
+WUtRa0ZOVkVJd1ZrSlZRMEpFVVZSRmQwaG9ZMDVOClZGbDNUVlJGZVUxVVJURk5SRVV4VjJoalRr
+MXFXWGROVkVFMVRWUkZNVTFFUlRGWGFrRlRUVkpCZHdwRVoxbEVWbEZSUkVWM1pFWlIKVmtGblVU
+QkZlRTFKU1VKSmFrRk9RbWRyY1docmFVYzVkekJDUVZGRlJrRkJUME5CVVRoQlRVbEpRa05uUzBO
+QlVVVkJDbnB1UVZCVgplakkyVFhOaFpUUjNjelF6WTNwU05ERXZTakpSZEhKVFNWcFZTMjFXVlhO
+V2RXMUVZbGxJY2xCT2RsUllTMU5OV0VGalpYZFBVa1JSCldWZ0tVbkYyU0had2JqaERjMk5DTVN0
+dlIxaGFka2gzZUdvMGVsWXdWMHR2U3pKNlpWaHJZWFV6ZG1ONWJETklTVXQxY0VwbWNUSlUKUlVG
+RFpXWldhbW93ZEFwS1Z5dFlNelZRUjFkd09TOUlOWHBKVlU1V1RsWnFVemRWYlhNNE5FbDJTMmhT
+UWpnMU1USlFRamxWZVVoaApaMWhaVmxnMVIxZHdRV05XY0hsbWNteFNDa1pKT1ZGa2FHZ3JVR0py
+TUhWNWEzUmtZbVl2UTJSbVowaFBiMlZpY2xSMGQxSnNhazB3CmIwUjBXQ3N5UTNZMmFqQjNRa3Mz
+YUVRNGNGQjJaakVyZFhrS1IzcGplbWxuUVZVdk5FdDNOMlZhY1hsa1pqbENLelZTZFhCU0swbGEK
+YVhCWU5ERjRSV2xKY2t0U2QzRnBOVEUzVjFkNldHTnFZVWN5WTA1aVpqUTFNUXA0Y0VnMVVHNVdN
+Mmt4ZEhFd05HcE5SMUZWZWtaMwpTVVJCVVVGQ2J6UkhRVTFJTkhkSVVWbEVWbEl3VDBKQ1dVVkdT
+WGRZTkhaek9FSnBRbU5UWTI5a0NqVnViMXBJVWswNFJUUXJhVTFGClNVZEJNVlZrU1hkUk4wMUVi
+VUZHU1hkWU5IWnpPRUpwUW1OVFkyOWtOVzV2V2toU1RUaEZOQ3RwYjFKaGEwWkVRVk1LVFZKQmQw
+Um4KV1VSV1VWRkVSWGRrUmxGV1FXZFJNRVY0WjJkclFXZDFWVll6UkUxMFZ6WnpkMFJCV1VSV1Vq
+QlVRa0ZWZDBGM1JVSXZla0ZNUW1kTwpWZ3BJVVRoRlFrRk5RMEZSV1hkRVVWbEtTMjlhU1doMlkw
+NUJVVVZNUWxGQlJHZG5SVUpCUm1aUmNVOVVRVGRTZGpkTEsyeDFVVGR3CmJtRnpORUpaZDBoRkNq
+bEhSVkF2ZFc5b2RqWkxUM2t3VkVkUlJtSnlVbFJxUm05TVZrNUNPVUphTVhsdFRVUmFNQzlVU1hk
+SlZXTTMKZDJrM1lUaDBOVzFGY1ZsSU1UVXpkMWNLWVZkdmIybFRhbmxNVEdoMVNUUnpUbkpPUTA5
+MGFYTmtRbkV5Y2pKTlJsaDBObWd3YlVGUgpXVTlRZGpoU09FczNMMlpuVTNoSFJuRjZhSGxPYlcx
+V1RBb3hjVUpLYkdSNE16UlRjSGR6VkVGTVVWWlFZalJvUjNkS2VscG1jakZRClkzQkZVWGcyZUUx
+dVZHdzRlRVZYV2tVelRYTTVPWFZoVlhoaVVYRkpkMUoxQ2t4blFVOXJUa050V1RKdE9EbFdhSHBo
+U0VveGRWWTQKTlVGa1RTOTBSQ3RaYzIxc2JtNXFkRGxNVWtObGFtSkNhWEJxU1VkcVQxaHlaekZL
+VUN0c2VGWUtiWFZOTkhaSUsxQXZiV3h0ZUhOUQpVSG93WkRZMVlpdEZSMjFLV25CdlRHdFBMM1Jr
+VGs1MlExbDZha3B3VkVWWGNFVnpUelpPVFdoTFdXODlDaTB0TFMwdFJVNUVJRU5GClVsUkpSa2xE
+UVZSRkxTMHRMUzBLCg==
\ No newline at end of file
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithNonBase64Part.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithNonBase64Part.base64
index 975f8e5..5c23f61 100644
--- a/wifi/tests/assets/hsr1/HSR1ProfileWithNonBase64Part.base64
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithNonBase64Part.base64
@@ -1,85 +1,86 @@
-Q29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5PXtib3VuZGFyeX0KQ29udGVu
-dC1UcmFuc2Zlci1FbmNvZGluZzogYmFzZTMyCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBh
-cHBsaWNhdGlvbi94LXBhc3Nwb2ludC1wcm9maWxlCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6
-IGJhc2U2NAoKUEUxbmJYUlVjbVZsSUhodGJHNXpQU0p6ZVc1amJXdzZaRzFrWkdZeExqSWlQZ29n
-SUR4V1pYSkVWRVErTVM0eVBDOVdaWEpFVkVRKwpDaUFnUEU1dlpHVStDaUFnSUNBOFRtOWtaVTVo
-YldVK1VHVnlVSEp2ZG1sa1pYSlRkV0p6WTNKcGNIUnBiMjQ4TDA1dlpHVk9ZVzFsClBnb2dJQ0Fn
-UEZKVVVISnZjR1Z5ZEdsbGN6NEtJQ0FnSUNBZ1BGUjVjR1UrQ2lBZ0lDQWdJQ0FnUEVSRVJrNWhi
-V1UrZFhKdU9uZG0KWVRwdGJ6cG9iM1J6Y0c5ME1tUnZkREF0Y0dWeWNISnZkbWxrWlhKemRXSnpZ
-M0pwY0hScGIyNDZNUzR3UEM5RVJFWk9ZVzFsUGdvZwpJQ0FnSUNBOEwxUjVjR1UrQ2lBZ0lDQThM
-MUpVVUhKdmNHVnlkR2xsY3o0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoCmJXVSth
-VEF3TVR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJSbFRt
-RnRaVDVJYjIxbFUxQTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lD
-QWdJQ0FnUEU1dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdApaVHd2VG05a1pVNWhiV1UrQ2lBZ0lD
-QWdJQ0FnSUNBOFZtRnNkV1UrUTJWdWRIVnllU0JJYjNWelpUd3ZWbUZzZFdVK0NpQWdJQ0FnCklD
-QWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcx
-bFBrWlJSRTQ4TDA1dlpHVk8KWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBtMXBOaTVqYnk1
-MWF6d3ZWbUZzZFdVK0NpQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZwpJQ0FnSUNBZ0lEeE9iMlJsUGdv
-Z0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsSnZZVzFwYm1kRGIyNXpiM0owYVhWdFQwazhMMDV2
-ClpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUGpFeE1qSXpNeXcwTkRVMU5qWThMMVpo
-YkhWbFBnb2dJQ0FnSUNBZ0lEd3YKVG05a1pUNEtJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0E4
-VG05a1pUNEtJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStRM0psWkdWdQpkR2xoYkR3dlRtOWtaVTVo
-YldVK0NpQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1VtVmhi
-RzA4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBuTm9ZV3RsYmk1emRHbHlj
-bVZrTG1OdmJUd3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9i
-MlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBsVnpaWEp1WVcxbApVR0Z6YzNkdmNtUThM
-MDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2Iy
-UmxUbUZ0ClpUNVZjMlZ5Ym1GdFpUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
-eDFaVDVxWVcxbGN6d3ZWbUZzZFdVK0NpQWcKSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lD
-QWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxCaApjM04zYjNKa1BD
-OU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQbGx0T1hWYVJFRjNUbmM5UFR3
-dlZtRnNkV1UrCkNpQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0
-S0lDQWdJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWwKUGtWQlVFMWxkR2h2WkR3dlRtOWtaVTVoYldV
-K0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0FnSUR4TwpiMlJsVG1G
-dFpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnSUNBOFZtRnNkV1Ur
-TWpFOEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnSUNBZ0lDQWdJQ0Fn
-SUR4T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRaVDVKYm01bGNrMWxkR2h2
-WkR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQazFUTFVOSQpRVkF0
-VmpJOEwxWmhiSFZsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThM
-MDV2WkdVK0NpQWdJQ0FnCklDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJ
-Q0FnSUNBZ1BFNXZaR1ZPWVcxbFBrUnBaMmwwWVd4RFpYSjAKYVdacFkyRjBaVHd2VG05a1pVNWhi
-V1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbApQ
-a05sY25ScFptbGpZWFJsVkhsd1pUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
-eDFaVDU0TlRBNWRqTThMMVpoCmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lD
-QWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEowVTBoQk1q
-VTJSbWx1WjJWeVVISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
-KwpNV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpG
-bU1XWXhaakZtTVdZeFpqRm1NV1l4ClpqRm1NV1l4Wmp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNB
-OEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWcKSUR4T2IyUmxQZ29nSUNB
-Z0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxOSlRUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4
-VG05awpaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbFBrbE5VMGs4TDA1dlpHVk9ZVzFs
-UGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzCmRXVSthVzF6YVR3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0Fn
-SUNBOEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWcKSUNBZ0lDQWdQRTV2
-WkdWT1lXMWxQa1ZCVUZSNWNHVThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBOFZtRnNk
-V1UrTWpROApMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEd3ZU
-bTlrWlQ0S0lDQWdJQ0FnUEM5T2IyUmxQZ29nCklDQWdQQzlPYjJSbFBnb2dJRHd2VG05a1pUNEtQ
-QzlOWjIxMFZISmxaVDRLCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94
-LXg1MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFD
-UlVkSlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtR
-VWxNYkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5U
-bFlLUWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpU
-azFxV1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5V
-VEJGZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMw
-TkJVVVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZY
-TldkVzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01T
-dHZSMWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJV
-RkRaV1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJo
-U1FqZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdK
-ck1IVjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtz
-M2FFUTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxh
-CmFYQllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVX
-TTJreGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZH
-U1hkWU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFF
-YlVGR1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJk
-MFJuCldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldV
-akJVUWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZ
-MDVCVVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZD
-amxIUlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNY
-ZEpWV00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1Ew
-OTBhWE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JX
-MVdUQW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVF
-MXVWR3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhw
-aFNFb3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpG
-S1VDdHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNS
-a1RrNTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmts
-RFFWUkZMUzB0TFMwSwotLXtib3VuZGFyeX0tLQo=
+TUlNRS1WZXJzaW9uOiAxLjAKQ29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5
+PXtib3VuZGFyeX07IGNoYXJzZXQ9VVRGLTgKQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogOGJp
+dAoKLS17Ym91bmRhcnl9CkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24veC1wYXNzcG9pbnQtcHJv
+ZmlsZTsgY2hhcnNldD1VVEYtOApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKClBF
+MW5iWFJVY21WbElIaHRiRzV6UFNKemVXNWpiV3c2Wkcxa1pHWXhMaklpUGdvZ0lEeFdaWEpFVkVR
+K01TNHlQQzlXWlhKRVZFUSsKQ2lBZ1BFNXZaR1UrQ2lBZ0lDQThUbTlrWlU1aGJXVStVR1Z5VUhK
+dmRtbGtaWEpUZFdKelkzSnBjSFJwYjI0OEwwNXZaR1ZPWVcxbApQZ29nSUNBZ1BGSlVVSEp2Y0dW
+eWRHbGxjejRLSUNBZ0lDQWdQRlI1Y0dVK0NpQWdJQ0FnSUNBZ1BFUkVSazVoYldVK2RYSnVPbmRt
+CllUcHRienBvYjNSemNHOTBNbVJ2ZERBdGNHVnljSEp2ZG1sa1pYSnpkV0p6WTNKcGNIUnBiMjQ2
+TVM0d1BDOUVSRVpPWVcxbFBnb2cKSUNBZ0lDQThMMVI1Y0dVK0NpQWdJQ0E4TDFKVVVISnZjR1Z5
+ZEdsbGN6NEtJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQThUbTlrWlU1aApiV1UrYVRBd01Ud3ZUbTlr
+WlU1aGJXVStDaUFnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUR4T2IyUmxUbUZ0WlQ1SWIyMWxV
+MUE4CkwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZa
+R1ZPWVcxbFBrWnlhV1Z1Wkd4NVRtRnQKWlR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQThW
+bUZzZFdVK1JYaGhiWEJzWlNCT1pYUjNiM0pyUEM5V1lXeDFaVDRLSUNBZwpJQ0FnSUNBOEwwNXZa
+R1UrQ2lBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrUmxGRVRq
+d3ZUbTlrClpVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBOFZtRnNkV1UrYUc5MGMzQnZkQzVsZUdGdGNH
+eGxMbTVsZER3dlZtRnNkV1UrQ2lBZ0lDQWcKSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUR4T2Iy
+UmxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGxKdllXMXBibWREYjI1egpiM0owYVhWdFQw
+azhMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQakV4TWpJek15dzBORFUxTmpZ
+OEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNB
+Z0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNBOFRtOWsKWlU1aGJXVStRM0psWkdWdWRHbGhiRHd2VG05
+a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4VG05awpaVTVoYldV
+K1VtVmhiRzA4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ1BGWmhiSFZsUG1WNFlXMXdiR1V1
+WTI5dFBDOVdZV3gxClpUNEtJQ0FnSUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZ1BFNXZaR1Ur
+Q2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVTVoYldVK1ZYTmwKY201aGJXVlFZWE56ZDI5eVpEd3ZUbTlr
+WlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEU1dgpaR1ZP
+WVcxbFBsVnpaWEp1WVcxbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQ
+blZ6WlhJOEwxWmhiSFZsClBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdQ
+RTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJSbFRtRnQKWlQ1UVlYTnpkMjl5WkR3dlRtOWta
+VTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJRHhXWVd4MVpUNWpSMFo2WXpOa2RtTnRVVDA4TDFaaApi
+SFZsUGdvZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lD
+QWdJQ0FnSUNBZ0lEeE9iMlJsClRtRnRaVDVGUVZCTlpYUm9iMlE4TDA1dlpHVk9ZVzFsUGdvZ0lD
+QWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNBZ0lDQWcKSUNBOFRtOWtaVTVoYldVK1JV
+RlFWSGx3WlR3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQakl4UEM5
+VwpZV3gxWlQ0S0lDQWdJQ0FnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4VG05
+a1pUNEtJQ0FnSUNBZ0lDQWdJQ0FnCklDQThUbTlrWlU1aGJXVStTVzV1WlhKTlpYUm9iMlE4TDA1
+dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQWdJRHhXWVd4MVpUNU4KVXkxRFNFRlFMVll5UEM5
+V1lXeDFaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BDOU9iMlJs
+UGdvZwpJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0Fn
+SUR4T2IyUmxUbUZ0WlQ1RWFXZHBkR0ZzClEyVnlkR2xtYVdOaGRHVThMMDV2WkdWT1lXMWxQZ29n
+SUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEow
+YVdacFkyRjBaVlI1Y0dVOEwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4Vm1Gc2RXVStl
+RFV3T1hZegpQQzlXWVd4MVpUNEtJQ0FnSUNBZ0lDQWdJRHd2VG05a1pUNEtJQ0FnSUNBZ0lDQWdJ
+RHhPYjJSbFBnb2dJQ0FnSUNBZ0lDQWdJQ0E4ClRtOWtaVTVoYldVK1EyVnlkRk5JUVRJMU5rWnBi
+bWRsY25CeWFXNTBQQzlPYjJSbFRtRnRaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BGWmgKYkhWbFBqRm1N
+V1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1X
+WXhaakZtTVdZeApaakZtTVdZeFpqRm1NV1k4TDFaaGJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2Iy
+UmxQZ29nSUNBZ0lDQWdJRHd2VG05a1pUNEtJQ0FnCklDQWdJQ0E4VG05a1pUNEtJQ0FnSUNBZ0lD
+QWdJRHhPYjJSbFRtRnRaVDVUU1UwOEwwNXZaR1ZPWVcxbFBnb2dJQ0FnSUNBZ0lDQWcKUEU1dlpH
+VStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmxUbUZ0WlQ1SlRWTkpQQzlPYjJSbFRtRnRaVDRLSUNB
+Z0lDQWdJQ0FnSUNBZwpQRlpoYkhWbFBqRXlNelExTmlvOEwxWmhiSFZsUGdvZ0lDQWdJQ0FnSUNB
+Z1BDOU9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ1BFNXZaR1UrCkNpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJS
+bFRtRnRaVDVGUVZCVWVYQmxQQzlPYjJSbFRtRnRaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BGWmgKYkhW
+bFBqSXpQQzlXWVd4MVpUNEtJQ0FnSUNBZ0lDQWdJRHd2VG05a1pUNEtJQ0FnSUNBZ0lDQThMMDV2
+WkdVK0NpQWdJQ0FnSUR3dgpUbTlrWlQ0S0lDQWdJRHd2VG05a1pUNEtJQ0E4TDA1dlpHVStDand2
+VFdkdGRGUnlaV1UrCgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94LXg1
+MDktY2EtY2VydApDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKCkxTMHRMUzFDUlVk
+SlRpQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENrMUpTVVJMUkVORFFXaERaMEYzU1VKQlowbEtRVWxN
+YkVaa2QzcE0KVm5WeVRVRXdSME5UY1VkVFNXSXpSRkZGUWtOM1ZVRk5Ra2w0UlVSQlQwSm5UbFlL
+UWtGTlZFSXdWa0pWUTBKRVVWUkZkMGhvWTA1TgpWRmwzVFZSRmVVMVVSVEZOUkVVeFYyaGpUazFx
+V1hkTlZFRTFUVlJGTVUxRVJURlhha0ZUVFZKQmR3cEVaMWxFVmxGUlJFVjNaRVpSClZrRm5VVEJG
+ZUUxSlNVSkpha0ZPUW1kcmNXaHJhVWM1ZHpCQ1FWRkZSa0ZCVDBOQlVUaEJUVWxKUWtOblMwTkJV
+VVZCQ25wdVFWQlYKZWpJMlRYTmhaVFIzY3pRelkzcFNOREV2U2pKUmRISlRTVnBWUzIxV1ZYTldk
+VzFFWWxsSWNsQk9kbFJZUzFOTldFRmpaWGRQVWtSUgpXVmdLVW5GMlNIWndiamhEYzJOQ01TdHZS
+MWhhZGtoM2VHbzBlbFl3VjB0dlN6SjZaVmhyWVhVemRtTjViRE5JU1V0MWNFcG1jVEpVClJVRkRa
+V1pXYW1vd2RBcEtWeXRZTXpWUVIxZHdPUzlJTlhwSlZVNVdUbFpxVXpkVmJYTTRORWwyUzJoU1Fq
+ZzFNVEpRUWpsVmVVaGgKWjFoWlZsZzFSMWR3UVdOV2NIbG1jbXhTQ2taSk9WRmthR2dyVUdKck1I
+VjVhM1JrWW1ZdlEyUm1aMGhQYjJWaWNsUjBkMUpzYWswdwpiMFIwV0NzeVEzWTJhakIzUWtzM2FF
+UTRjRkIyWmpFcmRYa0tSM3BqZW1sblFWVXZORXQzTjJWYWNYbGtaamxDS3pWU2RYQlNLMGxhCmFY
+QllOREY0UldsSmNrdFNkM0ZwTlRFM1YxZDZXR05xWVVjeVkwNWlaalExTVFwNGNFZzFVRzVXTTJr
+eGRIRXdOR3BOUjFGVmVrWjMKU1VSQlVVRkNielJIUVUxSU5IZElVVmxFVmxJd1QwSkNXVVZHU1hk
+WU5IWnpPRUpwUW1OVFkyOWtDalZ1YjFwSVVrMDRSVFFyYVUxRgpTVWRCTVZWa1NYZFJOMDFFYlVG
+R1NYZFlOSFp6T0VKcFFtTlRZMjlrTlc1dldraFNUVGhGTkN0cGIxSmhhMFpFUVZNS1RWSkJkMFJu
+CldVUldVVkZFUlhka1JsRldRV2RSTUVWNFoyZHJRV2QxVlZZelJFMTBWelp6ZDBSQldVUldVakJV
+UWtGVmQwRjNSVUl2ZWtGTVFtZE8KVmdwSVVUaEZRa0ZOUTBGUldYZEVVVmxLUzI5YVNXaDJZMDVC
+VVVWTVFsRkJSR2RuUlVKQlJtWlJjVTlVUVRkU2RqZExLMngxVVRkdwpibUZ6TkVKWmQwaEZDamxI
+UlZBdmRXOW9kalpMVDNrd1ZFZFJSbUp5VWxScVJtOU1WazVDT1VKYU1YbHRUVVJhTUM5VVNYZEpW
+V00zCmQyazNZVGgwTlcxRmNWbElNVFV6ZDFjS1lWZHZiMmxUYW5sTVRHaDFTVFJ6VG5KT1EwOTBh
+WE5rUW5FeWNqSk5SbGgwTm1nd2JVRlIKV1U5UWRqaFNPRXMzTDJablUzaEhSbkY2YUhsT2JXMVdU
+QW94Y1VKS2JHUjRNelJUY0hkelZFRk1VVlpRWWpSb1IzZEtlbHBtY2pGUQpZM0JGVVhnMmVFMXVW
+R3c0ZUVWWFdrVXpUWE01T1hWaFZYaGlVWEZKZDFKMUNreG5RVTlyVGtOdFdUSnRPRGxXYUhwaFNF
+b3hkVlk0Ck5VRmtUUzkwUkN0WmMyMXNibTVxZERsTVVrTmxhbUpDYVhCcVNVZHFUMWh5WnpGS1VD
+dHNlRllLYlhWTk5IWklLMUF2Yld4dGVITlEKVUhvd1pEWTFZaXRGUjIxS1duQnZUR3RQTDNSa1Rr
+NTJRMWw2YWtwd1ZFVlhjRVZ6VHpaT1RXaExXVzg5Q2kwdExTMHRSVTVFSUVORgpVbFJKUmtsRFFW
+UkZMUzB0TFMwSwotLXtib3VuZGFyeX0tLQo=
\ No newline at end of file
diff --git a/wifi/tests/assets/hsr1/HSR1ProfileWithUpdateIdentifier.base64 b/wifi/tests/assets/hsr1/HSR1ProfileWithUpdateIdentifier.base64
new file mode 100644
index 0000000..bab7607
--- /dev/null
+++ b/wifi/tests/assets/hsr1/HSR1ProfileWithUpdateIdentifier.base64
@@ -0,0 +1,88 @@
+TUlNRS1WZXJzaW9uOiAxLjAKQ29udGVudC1UeXBlOiBtdWx0aXBhcnQvbWl4ZWQ7IGJvdW5kYXJ5
+PXtib3VuZGFyeX07IGNoYXJzZXQ9VVRGLTgKQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogYmFz
+ZTY0CgotLXtib3VuZGFyeX0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94LXBhc3Nwb2ludC1w
+cm9maWxlOyBjaGFyc2V0PVVURi04CkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IGJhc2U2NAoK
+UEUxbmJYUlVjbVZsSUhodGJHNXpQU0p6ZVc1amJXdzZaRzFrWkdZeExqSWlQZ29nSUR4V1pYSkVW
+RVErTVM0eVBDOVdaWEpFVkVRKwpDaUFnUEU1dlpHVStDaUFnSUNBOFRtOWtaVTVoYldVK1VHVnlV
+SEp2ZG1sa1pYSlRkV0p6WTNKcGNIUnBiMjQ4TDA1dlpHVk9ZVzFsClBnb2dJQ0FnUEZKVVVISnZj
+R1Z5ZEdsbGN6NEtJQ0FnSUNBZ1BGUjVjR1UrQ2lBZ0lDQWdJQ0FnUEVSRVJrNWhiV1UrZFhKdU9u
+ZG0KWVRwdGJ6cG9iM1J6Y0c5ME1tUnZkREF0Y0dWeWNISnZkbWxrWlhKemRXSnpZM0pwY0hScGIy
+NDZNUzR3UEM5RVJFWk9ZVzFsUGdvZwpJQ0FnSUNBOEwxUjVjR1UrQ2lBZ0lDQThMMUpVVUhKdmNH
+VnlkR2xsY3o0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoCmJXVStWWEJrWVhSbFNX
+UmxiblJwWm1sbGNqd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lEeFdZV3gxWlQ0eE1qTTBQQzlXWVd4
+MVpUNEsKSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJRHhPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVTVoYldV
+K2FUQXdNVHd2VG05a1pVNWhiV1UrQ2lBZwpJQ0FnSUR4T2IyUmxQZ29nSUNBZ0lDQWdJRHhPYjJS
+bFRtRnRaVDVJYjIxbFUxQThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJRHhPCmIyUmxQZ29nSUNB
+Z0lDQWdJQ0FnUEU1dlpHVk9ZVzFsUGtaeWFXVnVaR3g1VG1GdFpUd3ZUbTlrWlU1aGJXVStDaUFn
+SUNBZ0lDQWcKSUNBOFZtRnNkV1UrUlhoaGJYQnNaU0JPWlhSM2IzSnJQQzlXWVd4MVpUNEtJQ0Fn
+SUNBZ0lDQThMMDV2WkdVK0NpQWdJQ0FnSUNBZwpQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQThUbTlr
+WlU1aGJXVStSbEZFVGp3dlRtOWtaVTVoYldVK0NpQWdJQ0FnSUNBZ0lDQThWbUZzCmRXVSthRzkw
+YzNCdmRDNWxlR0Z0Y0d4bExtNWxkRHd2Vm1Gc2RXVStDaUFnSUNBZ0lDQWdQQzlPYjJSbFBnb2dJ
+Q0FnSUNBZ0lEeE8KYjJSbFBnb2dJQ0FnSUNBZ0lDQWdQRTV2WkdWT1lXMWxQbEp2WVcxcGJtZERi
+MjV6YjNKMGFYVnRUMGs4TDA1dlpHVk9ZVzFsUGdvZwpJQ0FnSUNBZ0lDQWdQRlpoYkhWbFBqRXhN
+akl6TXl3ME5EVTFOalk4TDFaaGJIVmxQZ29nSUNBZ0lDQWdJRHd2VG05a1pUNEtJQ0FnCklDQWdQ
+QzlPYjJSbFBnb2dJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrUTNKbFpH
+VnVkR2xoYkR3dlRtOWsKWlU1aGJXVStDaUFnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lD
+QThUbTlrWlU1aGJXVStVbVZoYkcwOEwwNXZaR1ZPWVcxbApQZ29nSUNBZ0lDQWdJQ0FnUEZaaGJI
+VmxQbVY0WVcxd2JHVXVZMjl0UEM5V1lXeDFaVDRLSUNBZ0lDQWdJQ0E4TDA1dlpHVStDaUFnCklD
+QWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrVlhObGNtNWhiV1ZRWVhO
+emQyOXlaRHd2VG05a1pVNWgKYldVK0NpQWdJQ0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNB
+Z0lDQWdQRTV2WkdWT1lXMWxQbFZ6WlhKdVlXMWxQQzlPYjJSbApUbUZ0WlQ0S0lDQWdJQ0FnSUNB
+Z0lDQWdQRlpoYkhWbFBuVnpaWEk4TDFaaGJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29n
+CklDQWdJQ0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE9iMlJsVG1GdFpUNVFZWE56
+ZDI5eVpEd3ZUbTlrWlU1aGJXVSsKQ2lBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gxWlQ1alIwWjZZek5r
+ZG1OdFVUMDhMMVpoYkhWbFBnb2dJQ0FnSUNBZ0lDQWdQQzlPYjJSbApQZ29nSUNBZ0lDQWdJQ0Fn
+UEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmxUbUZ0WlQ1RlFWQk5aWFJvYjJROEwwNXZa
+R1ZPCllXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ0lDQThU
+bTlrWlU1aGJXVStSVUZRVkhsd1pUd3YKVG05a1pVNWhiV1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lDQWdQ
+RlpoYkhWbFBqSXhQQzlXWVd4MVpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEM5TwpiMlJsUGdvZ0lDQWdJ
+Q0FnSUNBZ0lDQThUbTlrWlQ0S0lDQWdJQ0FnSUNBZ0lDQWdJQ0E4VG05a1pVNWhiV1UrU1c1dVpY
+Sk5aWFJvCmIyUThMMDV2WkdWT1lXMWxQZ29nSUNBZ0lDQWdJQ0FnSUNBZ0lEeFdZV3gxWlQ1TlV5
+MURTRUZRTFZZeVBDOVdZV3gxWlQ0S0lDQWcKSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lD
+QWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJRHd2VG05a1pUNEtJQ0FnSUNBZwpJQ0E4VG05a1pU
+NEtJQ0FnSUNBZ0lDQWdJRHhPYjJSbFRtRnRaVDVFYVdkcGRHRnNRMlZ5ZEdsbWFXTmhkR1U4TDA1
+dlpHVk9ZVzFsClBnb2dJQ0FnSUNBZ0lDQWdQRTV2WkdVK0NpQWdJQ0FnSUNBZ0lDQWdJRHhPYjJS
+bFRtRnRaVDVEWlhKMGFXWnBZMkYwWlZSNWNHVTgKTDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNB
+Z0lDQThWbUZzZFdVK2VEVXdPWFl6UEM5V1lXeDFaVDRLSUNBZ0lDQWdJQ0FnSUR3dgpUbTlrWlQ0
+S0lDQWdJQ0FnSUNBZ0lEeE9iMlJsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThUbTlrWlU1aGJXVStRMlZ5
+ZEZOSVFUSTFOa1pwCmJtZGxjbkJ5YVc1MFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0Fn
+UEZaaGJIVmxQakZtTVdZeFpqRm1NV1l4WmpGbU1XWXgKWmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4
+WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZOEwxWmhiSFZsUGdvZwpJQ0Fn
+SUNBZ0lDQWdQQzlPYjJSbFBnb2dJQ0FnSUNBZ0lEd3ZUbTlrWlQ0S0lDQWdJQ0FnSUNBOFRtOWta
+VDRLSUNBZ0lDQWdJQ0FnCklEeE9iMlJsVG1GdFpUNVRTVTA4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJ
+Q0FnSUNBZ1BFNXZaR1UrQ2lBZ0lDQWdJQ0FnSUNBZ0lEeE8KYjJSbFRtRnRaVDVKVFZOSlBDOU9i
+MlJsVG1GdFpUNEtJQ0FnSUNBZ0lDQWdJQ0FnUEZaaGJIVmxQakV5TXpRMU5pbzhMMVpoYkhWbApQ
+Z29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lD
+QWdJQ0FnSUR4T2IyUmxUbUZ0ClpUNUZRVkJVZVhCbFBDOU9iMlJsVG1GdFpUNEtJQ0FnSUNBZ0lD
+QWdJQ0FnUEZaaGJIVmxQakl6UEM5V1lXeDFaVDRLSUNBZ0lDQWcKSUNBZ0lEd3ZUbTlrWlQ0S0lD
+QWdJQ0FnSUNBOEwwNXZaR1UrQ2lBZ0lDQWdJRHd2VG05a1pUNEtJQ0FnSUR3dlRtOWtaVDRLSUNB
+OApMMDV2WkdVK0Nqd3ZUV2R0ZEZSeVpXVSsKCi0te2JvdW5kYXJ5fQpDb250ZW50LVR5cGU6IGFw
+cGxpY2F0aW9uL3gteDUwOS1jYS1jZXJ0CkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IGJhc2U2
+NAoKTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVUkxSRU5EUVdoRFow
+RjNTVUpCWjBsS1FVbE1iRVprZDNwTQpWblZ5VFVFd1IwTlRjVWRUU1dJelJGRkZRa04zVlVGTlFr
+bDRSVVJCVDBKblRsWUtRa0ZOVkVJd1ZrSlZRMEpFVVZSRmQwaG9ZMDVOClZGbDNUVlJGZVUxVVJU
+Rk5SRVV4VjJoalRrMXFXWGROVkVFMVRWUkZNVTFFUlRGWGFrRlRUVkpCZHdwRVoxbEVWbEZSUkVW
+M1pFWlIKVmtGblVUQkZlRTFKU1VKSmFrRk9RbWRyY1docmFVYzVkekJDUVZGRlJrRkJUME5CVVRo
+QlRVbEpRa05uUzBOQlVVVkJDbnB1UVZCVgplakkyVFhOaFpUUjNjelF6WTNwU05ERXZTakpSZEhK
+VFNWcFZTMjFXVlhOV2RXMUVZbGxJY2xCT2RsUllTMU5OV0VGalpYZFBVa1JSCldWZ0tVbkYyU0ha
+d2JqaERjMk5DTVN0dlIxaGFka2gzZUdvMGVsWXdWMHR2U3pKNlpWaHJZWFV6ZG1ONWJETklTVXQx
+Y0VwbWNUSlUKUlVGRFpXWldhbW93ZEFwS1Z5dFlNelZRUjFkd09TOUlOWHBKVlU1V1RsWnFVemRW
+YlhNNE5FbDJTMmhTUWpnMU1USlFRamxWZVVoaApaMWhaVmxnMVIxZHdRV05XY0hsbWNteFNDa1pK
+T1ZGa2FHZ3JVR0pyTUhWNWEzUmtZbVl2UTJSbVowaFBiMlZpY2xSMGQxSnNhazB3CmIwUjBXQ3N5
+UTNZMmFqQjNRa3MzYUVRNGNGQjJaakVyZFhrS1IzcGplbWxuUVZVdk5FdDNOMlZhY1hsa1pqbENL
+elZTZFhCU0swbGEKYVhCWU5ERjRSV2xKY2t0U2QzRnBOVEUzVjFkNldHTnFZVWN5WTA1aVpqUTFN
+UXA0Y0VnMVVHNVdNMmt4ZEhFd05HcE5SMUZWZWtaMwpTVVJCVVVGQ2J6UkhRVTFJTkhkSVVWbEVW
+bEl3VDBKQ1dVVkdTWGRZTkhaek9FSnBRbU5UWTI5a0NqVnViMXBJVWswNFJUUXJhVTFGClNVZEJN
+VlZrU1hkUk4wMUViVUZHU1hkWU5IWnpPRUpwUW1OVFkyOWtOVzV2V2toU1RUaEZOQ3RwYjFKaGEw
+WkVRVk1LVFZKQmQwUm4KV1VSV1VWRkVSWGRrUmxGV1FXZFJNRVY0WjJkclFXZDFWVll6UkUxMFZ6
+WnpkMFJCV1VSV1VqQlVRa0ZWZDBGM1JVSXZla0ZNUW1kTwpWZ3BJVVRoRlFrRk5RMEZSV1hkRVVW
+bEtTMjlhU1doMlkwNUJVVVZNUWxGQlJHZG5SVUpCUm1aUmNVOVVRVGRTZGpkTEsyeDFVVGR3CmJt
+RnpORUpaZDBoRkNqbEhSVkF2ZFc5b2RqWkxUM2t3VkVkUlJtSnlVbFJxUm05TVZrNUNPVUphTVhs
+dFRVUmFNQzlVU1hkSlZXTTMKZDJrM1lUaDBOVzFGY1ZsSU1UVXpkMWNLWVZkdmIybFRhbmxNVEdo
+MVNUUnpUbkpPUTA5MGFYTmtRbkV5Y2pKTlJsaDBObWd3YlVGUgpXVTlRZGpoU09FczNMMlpuVTNo
+SFJuRjZhSGxPYlcxV1RBb3hjVUpLYkdSNE16UlRjSGR6VkVGTVVWWlFZalJvUjNkS2VscG1jakZR
+ClkzQkZVWGcyZUUxdVZHdzRlRVZYV2tVelRYTTVPWFZoVlhoaVVYRkpkMUoxQ2t4blFVOXJUa050
+V1RKdE9EbFdhSHBoU0VveGRWWTQKTlVGa1RTOTBSQ3RaYzIxc2JtNXFkRGxNVWtObGFtSkNhWEJx
+U1VkcVQxaHlaekZLVUN0c2VGWUtiWFZOTkhaSUsxQXZiV3h0ZUhOUQpVSG93WkRZMVlpdEZSMjFL
+V25CdlRHdFBMM1JrVGs1MlExbDZha3B3VkVWWGNFVnpUelpPVFdoTFdXODlDaTB0TFMwdFJVNUVJ
+RU5GClVsUkpSa2xEUVZSRkxTMHRMUzBLCi0te2JvdW5kYXJ5fS0tCg==
\ No newline at end of file
diff --git a/wifi/tests/assets/hsr1/README.txt b/wifi/tests/assets/hsr1/README.txt
index d1f8384..9f3cdc2 100644
--- a/wifi/tests/assets/hsr1/README.txt
+++ b/wifi/tests/assets/hsr1/README.txt
@@ -2,4 +2,5 @@
 HSR1ProfileWithCACert.base64 - base64 encoded of the data contained in HSR1ProfileWithCAWith.conf
 HSR1ProfileWithNonBase64Part.base64 - base64 encoded installation file that contains a part of non-base64 encoding type
 HSR1ProfileWithMissingBoundary.base64 - base64 encoded installation file with missing end-boundary in the MIME data
-HSR1ProfileWithInvalidContentType.base64 - base64 encoded installation file with that contains a MIME part with an invalid content type.
+HSR1ProfileWithInvalidContentType.base64 - base64 encoded installation file with that contains a MIME part with an invalid content type
+HSR1ProfileWithUpdateIdentifier.base64 - base64 encoded installation file with that contains an R2 update identifier
diff --git a/wifi/tests/src/android/net/wifi/ScanResultTest.java b/wifi/tests/src/android/net/wifi/ScanResultTest.java
index 54ec325..b5c74d1 100644
--- a/wifi/tests/src/android/net/wifi/ScanResultTest.java
+++ b/wifi/tests/src/android/net/wifi/ScanResultTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertNull;
 import static org.mockito.Mockito.validateMockitoUsage;
 
+import android.net.wifi.ScanResult.InformationElement;
 import android.os.Parcel;
 
 import androidx.test.filters.SmallTest;
@@ -41,6 +42,8 @@
     public static final int TEST_LEVEL = -56;
     public static final int TEST_FREQUENCY = 2412;
     public static final long TEST_TSF = 04660l;
+    public static final @ScanResult.WifiStandard int TEST_WIFI_STANDARD =
+            ScanResult.WIFI_STANDARD_11AC;
 
     /**
      * Setup before tests.
@@ -124,17 +127,38 @@
     }
 
     /**
+     * Verify parcel read/write for ScanResult with Information Element
+     */
+    @Test
+    public void verifyScanResultParcelWithInformationElement() throws Exception {
+        ScanResult writeScanResult = createScanResult();
+        writeScanResult.informationElements = new ScanResult.InformationElement[2];
+        writeScanResult.informationElements[0] = new ScanResult.InformationElement();
+        writeScanResult.informationElements[0].id = InformationElement.EID_HT_OPERATION;
+        writeScanResult.informationElements[0].idExt = 0;
+        writeScanResult.informationElements[0].bytes = new byte[]{0x11, 0x22, 0x33};
+        writeScanResult.informationElements[1] = new ScanResult.InformationElement();
+        writeScanResult.informationElements[1].id = InformationElement.EID_EXTENSION_PRESENT;
+        writeScanResult.informationElements[1].idExt = InformationElement.EID_EXT_HE_OPERATION;
+        writeScanResult.informationElements[1].bytes = new byte[]{0x44, 0x55, 0x66};
+        ScanResult readScanResult = new ScanResult(writeScanResult);
+        assertScanResultEquals(writeScanResult, readScanResult);
+    }
+
+    /**
      * Verify toString for ScanResult.
      */
     @Test
     public void verifyScanResultToStringWithoutRadioChainInfo() throws Exception {
         ScanResult scanResult = createScanResult();
-        assertEquals("SSID: \"test_ssid\", BSSID: 04:ac:fe:45:34:10, capabilities: CCMP, " +
-                "level: -56, frequency: 2412, timestamp: 2480, distance: 0(cm), distanceSd: 0(cm), " +
-                "passpoint: no, ChannelBandwidth: 0, centerFreq0: 0, centerFreq1: 0, " +
-                "80211mcResponder: is not supported, Carrier AP: no, " +
-                "Carrier AP EAP Type: 0, Carrier name: null, " +
-                "Radio Chain Infos: null", scanResult.toString());
+        assertEquals("SSID: \"test_ssid\", BSSID: 04:ac:fe:45:34:10, capabilities: CCMP, "
+                + "level: -56, frequency: 2412, timestamp: 2480, "
+                + "distance: 0(cm), distanceSd: 0(cm), "
+                + "passpoint: no, ChannelBandwidth: 0, centerFreq0: 0, centerFreq1: 0, "
+                + "standard: 11ac, "
+                + "80211mcResponder: is not supported, Carrier AP: no, "
+                + "Carrier AP EAP Type: 0, Carrier name: null, "
+                + "Radio Chain Infos: null", scanResult.toString());
     }
 
     /**
@@ -150,13 +174,15 @@
         scanResult.radioChainInfos[1] = new ScanResult.RadioChainInfo();
         scanResult.radioChainInfos[1].id = 1;
         scanResult.radioChainInfos[1].level = -54;
-        assertEquals("SSID: \"test_ssid\", BSSID: 04:ac:fe:45:34:10, capabilities: CCMP, " +
-                "level: -56, frequency: 2412, timestamp: 2480, distance: 0(cm), distanceSd: 0(cm), " +
-                "passpoint: no, ChannelBandwidth: 0, centerFreq0: 0, centerFreq1: 0, " +
-                "80211mcResponder: is not supported, Carrier AP: no, " +
-                "Carrier AP EAP Type: 0, Carrier name: null, " +
-                "Radio Chain Infos: [RadioChainInfo: id=0, level=-45, " +
-                "RadioChainInfo: id=1, level=-54]", scanResult.toString());
+        assertEquals("SSID: \"test_ssid\", BSSID: 04:ac:fe:45:34:10, capabilities: CCMP, "
+                + "level: -56, frequency: 2412, timestamp: 2480, distance: 0(cm), "
+                + "distanceSd: 0(cm), "
+                + "passpoint: no, ChannelBandwidth: 0, centerFreq0: 0, centerFreq1: 0, "
+                + "standard: 11ac, "
+                + "80211mcResponder: is not supported, Carrier AP: no, "
+                + "Carrier AP EAP Type: 0, Carrier name: null, "
+                + "Radio Chain Infos: [RadioChainInfo: id=0, level=-45, "
+                + "RadioChainInfo: id=1, level=-54]", scanResult.toString());
     }
 
     /**
@@ -177,6 +203,7 @@
         result.level = TEST_LEVEL;
         result.frequency = TEST_FREQUENCY;
         result.timestamp = TEST_TSF;
+        result.setWifiStandard(TEST_WIFI_STANDARD);
         return result;
     }
 
@@ -187,6 +214,8 @@
         assertEquals(expected.level, actual.level);
         assertEquals(expected.frequency, actual.frequency);
         assertEquals(expected.timestamp, actual.timestamp);
+        assertEquals(expected.getWifiStandard(), actual.getWifiStandard());
         assertArrayEquals(expected.radioChainInfos, actual.radioChainInfos);
+        assertArrayEquals(expected.informationElements, actual.informationElements);
     }
 }
diff --git a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
new file mode 100644
index 0000000..949b479
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.net.wifi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.net.MacAddress;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+@SmallTest
+public class SoftApConfigurationTest {
+    private SoftApConfiguration parcelUnparcel(SoftApConfiguration configIn) {
+        Parcel parcel = Parcel.obtain();
+        parcel.writeParcelable(configIn, 0);
+        parcel.setDataPosition(0);
+        SoftApConfiguration configOut =
+                parcel.readParcelable(SoftApConfiguration.class.getClassLoader());
+        parcel.recycle();
+        return configOut;
+    }
+
+    @Test
+    public void testBasicSettings() {
+        SoftApConfiguration original = new SoftApConfiguration.Builder()
+                .setSsid("ssid")
+                .setBssid(MacAddress.fromString("11:22:33:44:55:66"))
+                .build();
+        assertThat(original.getSsid()).isEqualTo("ssid");
+        assertThat(original.getBssid()).isEqualTo(MacAddress.fromString("11:22:33:44:55:66"));
+        assertThat(original.getWpa2Passphrase()).isNull();
+
+        SoftApConfiguration unparceled = parcelUnparcel(original);
+        assertThat(unparceled).isNotSameAs(original);
+        assertThat(unparceled).isEqualTo(original);
+        assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
+
+        SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
+        assertThat(copy).isNotSameAs(original);
+        assertThat(copy).isEqualTo(original);
+        assertThat(copy.hashCode()).isEqualTo(original.hashCode());
+    }
+
+    @Test
+    public void testWpa2() {
+        SoftApConfiguration original = new SoftApConfiguration.Builder()
+                .setWpa2Passphrase("secretsecret")
+                .build();
+        assertThat(original.getWpa2Passphrase()).isEqualTo("secretsecret");
+
+        SoftApConfiguration unparceled = parcelUnparcel(original);
+        assertThat(unparceled).isNotSameAs(original);
+        assertThat(unparceled).isEqualTo(original);
+        assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
+
+        SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
+        assertThat(copy).isNotSameAs(original);
+        assertThat(copy).isEqualTo(original);
+        assertThat(copy.hashCode()).isEqualTo(original.hashCode());
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiClientTest.java b/wifi/tests/src/android/net/wifi/WifiClientTest.java
new file mode 100644
index 0000000..42cab55
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiClientTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.net.wifi;
+
+import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
+import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.net.MacAddress;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiClient}.
+ */
+@SmallTest
+public class WifiClientTest {
+    private static final String INTERFACE_NAME = "wlan0";
+    private static final String MAC_ADDRESS_STRING = "00:0a:95:9d:68:16";
+    private static final MacAddress MAC_ADDRESS = MacAddress.fromString(MAC_ADDRESS_STRING);
+
+    /**
+     *  Verify parcel write/read with WifiClient.
+     */
+    @Test
+    public void testWifiClientParcelWriteRead() throws Exception {
+        WifiClient writeWifiClient = new WifiClient(MAC_ADDRESS);
+
+        assertParcelSane(writeWifiClient, 1);
+    }
+
+    /**
+     *  Verify equals with WifiClient.
+     */
+    @Test
+    public void testWifiClientEquals() throws Exception {
+        WifiClient writeWifiClient = new WifiClient(MAC_ADDRESS);
+        WifiClient writeWifiClientEquals = new WifiClient(MAC_ADDRESS);
+
+        assertEquals(writeWifiClient, writeWifiClientEquals);
+        assertEquals(writeWifiClient.hashCode(), writeWifiClientEquals.hashCode());
+        assertFieldCountEquals(1, WifiClient.class);
+    }
+
+    /**
+     *  Verify not-equals with WifiClient.
+     */
+    @Test
+    public void testWifiClientNotEquals() throws Exception {
+        final MacAddress macAddressNotEquals = MacAddress.fromString("00:00:00:00:00:00");
+        WifiClient writeWifiClient = new WifiClient(MAC_ADDRESS);
+        WifiClient writeWifiClientNotEquals = new WifiClient(macAddressNotEquals);
+
+        assertNotEquals(writeWifiClient, writeWifiClientNotEquals);
+        assertNotEquals(writeWifiClient.hashCode(), writeWifiClientNotEquals.hashCode());
+    }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiInfoTest.java b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
index ea08ea8..22a5faa 100644
--- a/wifi/tests/src/android/net/wifi/WifiInfoTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
@@ -38,7 +38,7 @@
     private static final String TEST_PACKAGE_NAME = "com.test.example";
     private static final String TEST_FQDN = "test.com";
     private static final String TEST_PROVIDER_NAME = "test";
-    private static final int TEST_WIFI_TECHNOLOGY = WifiInfo.WIFI_TECHNOLOGY_11AC;
+    private static final int TEST_WIFI_STANDARD = ScanResult.WIFI_STANDARD_11AC;
 
     /**
      *  Verify parcel write/read with WifiInfo.
@@ -55,7 +55,7 @@
         writeWifiInfo.setFQDN(TEST_FQDN);
         writeWifiInfo.setProviderFriendlyName(TEST_PROVIDER_NAME);
         writeWifiInfo.setNetworkSuggestionOrSpecifierPackageName(TEST_PACKAGE_NAME);
-        writeWifiInfo.setWifiTechnology(TEST_WIFI_TECHNOLOGY);
+        writeWifiInfo.setWifiStandard(TEST_WIFI_STANDARD);
 
         Parcel parcel = Parcel.obtain();
         writeWifiInfo.writeToParcel(parcel, 0);
@@ -74,6 +74,6 @@
         assertEquals(TEST_PACKAGE_NAME, readWifiInfo.getNetworkSuggestionOrSpecifierPackageName());
         assertEquals(TEST_FQDN, readWifiInfo.getPasspointFqdn());
         assertEquals(TEST_PROVIDER_NAME, readWifiInfo.getPasspointProviderFriendlyName());
-        assertEquals(TEST_WIFI_TECHNOLOGY, readWifiInfo.getWifiTechnology());
+        assertEquals(TEST_WIFI_STANDARD, readWifiInfo.getWifiStandard());
     }
 }
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index f8a0c8f..d2516a3 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -99,8 +99,7 @@
     private static final String[] TEST_MAC_ADDRESSES = {"da:a1:19:0:0:0"};
 
     @Mock Context mContext;
-    @Mock
-    android.net.wifi.IWifiManager mWifiService;
+    @Mock android.net.wifi.IWifiManager mWifiService;
     @Mock ApplicationInfo mApplicationInfo;
     @Mock WifiConfiguration mApConfig;
     @Mock SoftApCallback mSoftApCallback;
@@ -115,7 +114,8 @@
     private TestLooper mLooper;
     private WifiManager mWifiManager;
 
-    @Before public void setUp() throws Exception {
+    @Before
+    public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         mLooper = new TestLooper();
         mHandler = spy(new Handler(mLooper.getLooper()));
@@ -173,7 +173,7 @@
     public void testCreationAndCloseOfLocalOnlyHotspotReservation() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
-                anyString())).thenReturn(REQUEST_REGISTERED);
+                anyString(), eq(null))).thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
 
         callback.onStarted(mWifiManager.new LocalOnlyHotspotReservation(mApConfig));
@@ -191,7 +191,7 @@
             throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
-                anyString())).thenReturn(REQUEST_REGISTERED);
+                anyString(), eq(null))).thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
 
         callback.onStarted(mWifiManager.new LocalOnlyHotspotReservation(mApConfig));
@@ -210,7 +210,7 @@
     @Test
     public void testCreationOfLocalOnlyHotspotSubscription() throws Exception {
         try (WifiManager.LocalOnlyHotspotSubscription sub =
-                mWifiManager.new LocalOnlyHotspotSubscription()) {
+                     mWifiManager.new LocalOnlyHotspotSubscription()) {
             sub.close();
         }
     }
@@ -351,7 +351,7 @@
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
 
         verify(mWifiService)
-                .startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString());
+                .startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(), eq(null));
     }
 
     /**
@@ -362,7 +362,7 @@
     public void testStartLocalOnlyHotspotThrowsSecurityException() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         doThrow(new SecurityException()).when(mWifiService)
-                .startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString());
+                .startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(), eq(null));
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
     }
 
@@ -374,7 +374,7 @@
     public void testStartLocalOnlyHotspotThrowsIllegalStateException() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         doThrow(new IllegalStateException()).when(mWifiService)
-                .startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString());
+                .startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(), eq(null));
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
     }
 
@@ -385,7 +385,7 @@
     public void testCorrectLooperIsUsedForHandler() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
-                anyString())).thenReturn(ERROR_INCOMPATIBLE_MODE);
+                anyString(), eq(null))).thenReturn(ERROR_INCOMPATIBLE_MODE);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mLooper.dispatchAll();
         assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason);
@@ -404,7 +404,7 @@
         when(mContext.getMainExecutor()).thenReturn(altLooper.getNewExecutor());
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
-                anyString())).thenReturn(ERROR_INCOMPATIBLE_MODE);
+                anyString(), eq(null))).thenReturn(ERROR_INCOMPATIBLE_MODE);
         mWifiManager.startLocalOnlyHotspot(callback, null);
         altLooper.dispatchAll();
         assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason);
@@ -423,7 +423,7 @@
         Handler callbackHandler = new Handler(callbackLooper.getLooper());
         ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
                 ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
-        when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString()))
+        when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString(), eq(null)))
                 .thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, callbackHandler);
         callbackLooper.dispatchAll();
@@ -449,7 +449,7 @@
         Handler callbackHandler = new Handler(callbackLooper.getLooper());
         ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
                 ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
-        when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString()))
+        when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString(), eq(null)))
                 .thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, callbackHandler);
         callbackLooper.dispatchAll();
@@ -474,7 +474,7 @@
         Handler callbackHandler = new Handler(callbackLooper.getLooper());
         ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
                 ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
-        when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString()))
+        when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString(), eq(null)))
                 .thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, callbackHandler);
         callbackLooper.dispatchAll();
@@ -497,7 +497,7 @@
         Handler callbackHandler = new Handler(callbackLooper.getLooper());
         ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
                 ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
-        when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString()))
+        when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString(), eq(null)))
                 .thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, callbackHandler);
         callbackLooper.dispatchAll();
@@ -517,7 +517,7 @@
     public void testLocalOnlyHotspotCallbackFullOnIncompatibleMode() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
-                anyString())).thenReturn(ERROR_INCOMPATIBLE_MODE);
+                anyString(), eq(null))).thenReturn(ERROR_INCOMPATIBLE_MODE);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mLooper.dispatchAll();
         assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason);
@@ -533,7 +533,7 @@
     public void testLocalOnlyHotspotCallbackFullOnTetheringDisallowed() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
-                anyString())).thenReturn(ERROR_TETHERING_DISALLOWED);
+                anyString(), eq(null))).thenReturn(ERROR_TETHERING_DISALLOWED);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mLooper.dispatchAll();
         assertEquals(ERROR_TETHERING_DISALLOWED, callback.mFailureReason);
@@ -550,7 +550,7 @@
     public void testLocalOnlyHotspotCallbackFullOnSecurityException() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         doThrow(new SecurityException()).when(mWifiService)
-                .startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString());
+                .startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(), eq(null));
         try {
             mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         } catch (SecurityException e) {
@@ -571,7 +571,7 @@
     public void testLocalOnlyHotspotCallbackFullOnNoChannelError() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
-                anyString())).thenReturn(REQUEST_REGISTERED);
+                anyString(), eq(null))).thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mLooper.dispatchAll();
         //assertEquals(ERROR_NO_CHANNEL, callback.mFailureReason);
@@ -587,7 +587,7 @@
     public void testCancelLocalOnlyHotspotRequestCallsStopOnWifiService() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
-                anyString())).thenReturn(REQUEST_REGISTERED);
+                anyString(), eq(null))).thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mWifiManager.cancelLocalOnlyHotspotRequest();
         verify(mWifiService).stopLocalOnlyHotspot();
@@ -609,7 +609,7 @@
     public void testCallbackAfterLocalOnlyHotspotWasCancelled() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
-                anyString())).thenReturn(REQUEST_REGISTERED);
+                anyString(), eq(null))).thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mWifiManager.cancelLocalOnlyHotspotRequest();
         verify(mWifiService).stopLocalOnlyHotspot();
@@ -628,7 +628,7 @@
     public void testCancelAfterLocalOnlyHotspotCallbackTriggered() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
-                anyString())).thenReturn(ERROR_INCOMPATIBLE_MODE);
+                anyString(), eq(null))).thenReturn(ERROR_INCOMPATIBLE_MODE);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mLooper.dispatchAll();
         assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason);
@@ -639,6 +639,17 @@
         verify(mWifiService, never()).stopLocalOnlyHotspot();
     }
 
+    @Test
+    public void testStartLocalOnlyHotspotForwardsCustomConfig() throws Exception {
+        SoftApConfiguration customConfig = new SoftApConfiguration.Builder()
+                .setSsid("customSsid")
+                .build();
+        TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
+        mWifiManager.startLocalOnlyHotspot(customConfig, mExecutor, callback);
+        verify(mWifiService).startLocalOnlyHotspot(
+                any(ILocalOnlyHotspotCallback.class), anyString(), eq(customConfig));
+    }
+
     /**
      * Verify the watchLocalOnlyHotspot call goes to WifiServiceImpl.
      */
@@ -752,17 +763,17 @@
      * Verify client-provided callback is being called through callback proxy
      */
     @Test
-    public void softApCallbackProxyCallsOnNumClientsChanged() throws Exception {
+    public void softApCallbackProxyCallsOnConnectedClientsChanged() throws Exception {
         ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
                 ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
         mWifiManager.registerSoftApCallback(mSoftApCallback, mHandler);
         verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
                 anyInt());
 
-        final int testNumClients = 3;
-        callbackCaptor.getValue().onNumClientsChanged(testNumClients);
+        final List<WifiClient> testClients = new ArrayList();
+        callbackCaptor.getValue().onConnectedClientsChanged(testClients);
         mLooper.dispatchAll();
-        verify(mSoftApCallback).onNumClientsChanged(testNumClients);
+        verify(mSoftApCallback).onConnectedClientsChanged(testClients);
     }
 
     /*
@@ -776,14 +787,14 @@
         verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
                 anyInt());
 
-        final int testNumClients = 5;
+        final List<WifiClient> testClients = new ArrayList();
         callbackCaptor.getValue().onStateChanged(WIFI_AP_STATE_ENABLING, 0);
-        callbackCaptor.getValue().onNumClientsChanged(testNumClients);
+        callbackCaptor.getValue().onConnectedClientsChanged(testClients);
         callbackCaptor.getValue().onStateChanged(WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL);
 
         mLooper.dispatchAll();
         verify(mSoftApCallback).onStateChanged(WIFI_AP_STATE_ENABLING, 0);
-        verify(mSoftApCallback).onNumClientsChanged(testNumClients);
+        verify(mSoftApCallback).onConnectedClientsChanged(testClients);
         verify(mSoftApCallback).onStateChanged(WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL);
     }
 
@@ -1020,8 +1031,8 @@
         verifyNoMoreInteractions(mWifiService);
     }
 
-   /**
-i     * Verify that a call to cancel WPS immediately returns a failure.
+    /**
+     * Verify that a call to cancel WPS immediately returns a failure.
      */
     @Test
     public void testCancelWpsImmediatelyFailsWithCallback() {
@@ -1324,7 +1335,6 @@
 
     /**
      * Verify getting the factory MAC address.
-     * @throws Exception
      */
     @Test
     public void testGetFactoryMacAddress() throws Exception {
@@ -1371,7 +1381,6 @@
 
     /**
      * Test behavior of isEnhancedOpenSupported
-     * @throws Exception
      */
     @Test
     public void testIsEnhancedOpenSupported() throws Exception {
@@ -1385,7 +1394,6 @@
 
     /**
      * Test behavior of isWpa3SaeSupported
-     * @throws Exception
      */
     @Test
     public void testIsWpa3SaeSupported() throws Exception {
@@ -1399,7 +1407,6 @@
 
     /**
      * Test behavior of isWpa3SuiteBSupported
-     * @throws Exception
      */
     @Test
     public void testIsWpa3SuiteBSupported() throws Exception {
@@ -1413,7 +1420,6 @@
 
     /**
      * Test behavior of isEasyConnectSupported
-     * @throws Exception
      */
     @Test
     public void testIsEasyConnectSupported() throws Exception {
@@ -1427,7 +1433,6 @@
 
     /**
      * Test behavior of {@link WifiManager#addNetwork(WifiConfiguration)}
-     * @throws Exception
      */
     @Test
     public void testAddNetwork() throws Exception {
@@ -1444,7 +1449,6 @@
 
     /**
      * Test behavior of {@link WifiManager#addNetwork(WifiConfiguration)}
-     * @throws Exception
      */
     @Test
     public void testUpdateNetwork() throws Exception {
@@ -1466,7 +1470,6 @@
 
     /**
      * Test behavior of {@link WifiManager#enableNetwork(int, boolean)}
-     * @throws Exception
      */
     @Test
     public void testEnableNetwork() throws Exception {
@@ -1478,7 +1481,6 @@
 
     /**
      * Test behavior of {@link WifiManager#disableNetwork(int)}
-     * @throws Exception
      */
     @Test
     public void testDisableNetwork() throws Exception {
@@ -1489,10 +1491,19 @@
     }
 
     /**
-     * Test behavior of {@link WifiManager#disconnect()}
+     * Test behavior of {@link WifiManager#allowAutojoin(int, boolean)}
      * @throws Exception
      */
     @Test
+    public void testAllowAutojoin() throws Exception {
+        mWifiManager.allowAutojoin(1, true);
+        verify(mWifiService).allowAutojoin(eq(1), eq(true));
+    }
+
+    /**
+     * Test behavior of {@link WifiManager#disconnect()}
+     */
+    @Test
     public void testDisconnect() throws Exception {
         when(mWifiService.disconnect(anyString())).thenReturn(true);
         assertTrue(mWifiManager.disconnect());
@@ -1501,7 +1512,6 @@
 
     /**
      * Test behavior of {@link WifiManager#reconnect()}
-     * @throws Exception
      */
     @Test
     public void testReconnect() throws Exception {
@@ -1512,7 +1522,6 @@
 
     /**
      * Test behavior of {@link WifiManager#reassociate()}
-     * @throws Exception
      */
     @Test
     public void testReassociate() throws Exception {
@@ -1523,7 +1532,6 @@
 
     /**
      * Test behavior of {@link WifiManager#getSupportedFeatures()}
-     * @throws Exception
      */
     @Test
     public void testGetSupportedFeatures() throws Exception {
@@ -1550,7 +1558,6 @@
 
     /**
      * Test behavior of {@link WifiManager#getControllerActivityEnergyInfo()}
-     * @throws Exception
      */
     @Test
     public void testGetControllerActivityEnergyInfo() throws Exception {
@@ -1563,7 +1570,6 @@
 
     /**
      * Test behavior of {@link WifiManager#getConnectionInfo()}
-     * @throws Exception
      */
     @Test
     public void testGetConnectionInfo() throws Exception {
@@ -1575,7 +1581,6 @@
 
     /**
      * Test behavior of {@link WifiManager#isDualModeSupported()} ()}
-     * @throws Exception
      */
     @Test
     public void testIsDualModeSupported() throws Exception {
@@ -1586,7 +1591,6 @@
 
     /**
      * Test behavior of {@link WifiManager#isDualBandSupported()}
-     * @throws Exception
      */
     @Test
     public void testIsDualBandSupported() throws Exception {
@@ -1597,7 +1601,6 @@
 
     /**
      * Test behavior of {@link WifiManager#getDhcpInfo()}
-     * @throws Exception
      */
     @Test
     public void testGetDhcpInfo() throws Exception {
@@ -1610,7 +1613,6 @@
 
     /**
      * Test behavior of {@link WifiManager#setWifiEnabled(boolean)}
-     * @throws Exception
      */
     @Test
     public void testSetWifiEnabled() throws Exception {
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java b/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java
index d9a1d9af..439e672 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java
@@ -54,6 +54,8 @@
             "assets/hsr1/HSR1ProfileWithInvalidContentType.base64";
     private static final String PASSPOINT_INSTALLATION_FILE_WITHOUT_PROFILE =
             "assets/hsr1/HSR1ProfileWithoutProfile.base64";
+    private static final String PASSPOINT_INSTALLATION_FILE_WITH_UPDATE_ID =
+            "assets/hsr1/HSR1ProfileWithUpdateIdentifier.base64";
 
     /**
      * Read the content of the given resource file into a String.
@@ -85,17 +87,17 @@
 
         // HomeSP configuration.
         HomeSp homeSp = new HomeSp();
-        homeSp.setFriendlyName("Century House");
-        homeSp.setFqdn("mi6.co.uk");
+        homeSp.setFriendlyName("Example Network");
+        homeSp.setFqdn("hotspot.example.net");
         homeSp.setRoamingConsortiumOis(new long[] {0x112233L, 0x445566L});
         config.setHomeSp(homeSp);
 
         // Credential configuration.
         Credential credential = new Credential();
-        credential.setRealm("shaken.stirred.com");
+        credential.setRealm("example.com");
         Credential.UserCredential userCredential = new Credential.UserCredential();
-        userCredential.setUsername("james");
-        userCredential.setPassword("Ym9uZDAwNw==");
+        userCredential.setUsername("user");
+        userCredential.setPassword("cGFzc3dvcmQ=");
         userCredential.setEapType(21);
         userCredential.setNonEapInnerMethod("MS-CHAP-V2");
         credential.setUserCredential(userCredential);
@@ -106,8 +108,8 @@
         certCredential.setCertSha256Fingerprint(certSha256Fingerprint);
         credential.setCertCredential(certCredential);
         Credential.SimCredential simCredential = new Credential.SimCredential();
-        simCredential.setImsi("imsi");
-        simCredential.setEapType(24);
+        simCredential.setImsi("123456*");
+        simCredential.setEapType(23);
         credential.setSimCredential(simCredential);
         credential.setCaCertificate(FakeKeys.CA_CERT0);
         config.setCredential(credential);
@@ -201,4 +203,21 @@
         assertNull(ConfigParser.parsePasspointConfig(
                 "application/x-wifi-config", configStr.getBytes()));
     }
+
+    /**
+     * Verify a valid installation file is parsed successfully with the matching contents, and that
+     * Update identifier is cleared.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void parseConfigFileWithUpdateIdentifier() throws Exception {
+        String configStr = loadResourceFile(PASSPOINT_INSTALLATION_FILE_WITH_UPDATE_ID);
+        PasspointConfiguration expectedConfig = generateConfigurationFromProfile();
+        PasspointConfiguration actualConfig =
+                ConfigParser.parsePasspointConfig(
+                        "application/x-wifi-config", configStr.getBytes());
+        // Expected configuration does not contain an update identifier
+        assertTrue(actualConfig.equals(expectedConfig));
+    }
 }
\ No newline at end of file
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index c3b074e..f501b16 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -183,7 +183,7 @@
         PasspointConfiguration config = PasspointTestUtils.createConfig();
 
         assertTrue(config.validate());
-        assertTrue(config.validateForR2());
+        assertFalse(config.isOsuProvisioned());
     }
 
     /**
@@ -241,7 +241,6 @@
         config.setPolicy(null);
 
         assertTrue(config.validate());
-        assertTrue(config.validateForR2());
     }
 
     /**
@@ -271,7 +270,6 @@
         config.setAaaServerTrustedNames(null);
 
         assertTrue(config.validate());
-        assertTrue(config.validateForR2());
     }
 
     /**
@@ -348,4 +346,17 @@
         PasspointConfiguration copyConfig = new PasspointConfiguration(sourceConfig);
         assertTrue(copyConfig.equals(sourceConfig));
     }
+
+    /**
+     * Verify that a configuration containing all fields is valid for R2.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void validateFullR2Config() throws Exception {
+        PasspointConfiguration config = PasspointTestUtils.createR2Config();
+        assertTrue(config.validate());
+        assertTrue(config.validateForR2());
+        assertTrue(config.isOsuProvisioned());
+    }
 }
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointTestUtils.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointTestUtils.java
index adf74eb..8d55acb 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointTestUtils.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointTestUtils.java
@@ -132,7 +132,6 @@
      */
     public static PasspointConfiguration createConfig() {
         PasspointConfiguration config = new PasspointConfiguration();
-        config.setUpdateIdentifier(1234);
         config.setHomeSp(createHomeSp());
         config.setAaaServerTrustedNames(
                 new String[] {"trusted.fqdn.com", "another-trusted.fqdn.com"});
@@ -145,7 +144,6 @@
         trustRootCertList.put("trustRoot.cert2.com",
                 new byte[CERTIFICATE_FINGERPRINT_BYTES]);
         config.setTrustRootCertList(trustRootCertList);
-        config.setUpdateIdentifier(1);
         config.setCredentialPriority(120);
         config.setSubscriptionCreationTimeInMillis(231200);
         config.setSubscriptionExpirationTimeInMillis(2134232);
@@ -160,4 +158,15 @@
         config.setServiceFriendlyNames(friendlyNames);
         return config;
     }
+
+    /**
+     * Helper function for creating an R2 {@link PasspointConfiguration} for testing.
+     *
+     * @return {@link PasspointConfiguration}
+     */
+    public static PasspointConfiguration createR2Config() {
+        PasspointConfiguration config = createConfig();
+        config.setUpdateIdentifier(1234);
+        return config;
+    }
 }