Merge "Enable filesystem checkpoint for staged apk installation"
diff --git a/Android.bp b/Android.bp
index e1f5abd9..25c643d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -451,6 +451,16 @@
     // For backwards compatibility.
     stem: "framework",
     apex_available: ["//apex_available:platform"],
+    visibility: [
+        "//frameworks/base",
+        // TODO(b/144149403) remove the below lines
+        "//frameworks/base/apex/appsearch/framework",
+        "//frameworks/base/apex/blobstore/framework",
+        "//frameworks/base/apex/jobscheduler/framework",
+        "//frameworks/base/apex/statsd/service",
+        "//frameworks/base/wifi",
+        "//frameworks/opt/net/wifi/service",
+    ],
 }
 
 // This "framework" module is NOT installed to the device. It's
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 78e72bf..4d1ac0e 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -6,6 +6,7 @@
 clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
                cmds/hid/
                cmds/input/
+               core/jni/
                libs/input/
 
 [Hook Scripts]
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 1ec96ec..9310762 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -81,7 +81,6 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.Preconditions;
 import com.android.server.AppStateTracker;
 import com.android.server.DeviceIdleInternal;
 import com.android.server.FgThread;
@@ -117,6 +116,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Objects;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 
@@ -1283,7 +1283,7 @@
         super(context);
 
         mLocalPM = LocalServices.getService(PackageManagerInternal.class);
-        mActivityManagerInternal = Preconditions.checkNotNull(
+        mActivityManagerInternal = Objects.requireNonNull(
                 LocalServices.getService(ActivityManagerInternal.class));
 
         mHandler = new JobHandler(context.getMainLooper());
@@ -1389,7 +1389,7 @@
                 controller.onSystemServicesReady();
             }
 
-            mAppStateTracker = Preconditions.checkNotNull(
+            mAppStateTracker = Objects.requireNonNull(
                     LocalServices.getService(AppStateTracker.class));
 
             // Register br for package removals and user removals.
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
index 8b61006..aa3d74a 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -23,7 +23,6 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.Preconditions;
 import com.android.server.AppStateTracker;
 import com.android.server.AppStateTracker.Listener;
 import com.android.server.LocalServices;
@@ -32,6 +31,7 @@
 import com.android.server.job.StateControllerProto;
 import com.android.server.job.StateControllerProto.BackgroundJobsController.TrackedJob;
 
+import java.util.Objects;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 
@@ -59,7 +59,7 @@
     public BackgroundJobsController(JobSchedulerService service) {
         super(service);
 
-        mAppStateTracker = Preconditions.checkNotNull(
+        mAppStateTracker = Objects.requireNonNull(
                 LocalServices.getService(AppStateTracker.class));
         mAppStateTracker.addListener(mForceAppStandbyListener);
     }
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 7ed51ca..e4f7300 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -23,7 +23,6 @@
 import static android.os.storage.VolumeInfo.TYPE_PRIVATE;
 import static android.os.storage.VolumeInfo.TYPE_PUBLIC;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
 import static com.android.server.stats.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
 import static com.android.server.stats.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
@@ -1848,7 +1847,7 @@
             int tagId, long elapsedNanos, long wallClockNanos,
             List<StatsLogEventWrapper> pulledData) {
         PowerProfile powerProfile = new PowerProfile(mContext);
-        checkNotNull(powerProfile);
+        Objects.requireNonNull(powerProfile);
 
         StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
                 wallClockNanos);
diff --git a/api/current.txt b/api/current.txt
index c734db5..9425b81 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -91,6 +91,7 @@
     field public static final String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES";
     field public static final String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
     field public static final String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
+    field public static final String MANAGE_EXTERNAL_STORAGE = "android.permission.MANAGE_EXTERNAL_STORAGE";
     field public static final String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS";
     field public static final String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
     field public static final String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL";
@@ -610,6 +611,7 @@
     field public static final int fastScrollTextColor = 16843609; // 0x1010359
     field public static final int fastScrollThumbDrawable = 16843574; // 0x1010336
     field public static final int fastScrollTrackDrawable = 16843577; // 0x1010339
+    field public static final int featureId = 16844301; // 0x101060d
     field public static final int fillAfter = 16843197; // 0x10101bd
     field public static final int fillAlpha = 16843980; // 0x10104cc
     field public static final int fillBefore = 16843196; // 0x10101bc
@@ -1331,6 +1333,7 @@
     field public static final int summaryOff = 16843248; // 0x10101f0
     field public static final int summaryOn = 16843247; // 0x10101ef
     field public static final int supportsAssist = 16844016; // 0x10104f0
+    field public static final int supportsInlineSuggestions = 16844302; // 0x101060e
     field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
     field public static final int supportsLocalInteraction = 16844047; // 0x101050f
     field public static final int supportsMultipleDisplays = 16844182; // 0x1010596
@@ -4498,7 +4501,6 @@
     method public int describeContents();
     method @Nullable public String getFeatureId();
     method @NonNull public String getMessage();
-    method @Nullable public String getNotingPackageName();
     method @IntRange(from=0) public int getNotingUid();
     method @NonNull public String getOp();
     method @IntRange(from=0) public long getTime();
diff --git a/api/system-current.txt b/api/system-current.txt
index 8a888db..6b2aea5 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -111,6 +111,7 @@
     field public static final String MANAGE_CONTENT_SUGGESTIONS = "android.permission.MANAGE_CONTENT_SUGGESTIONS";
     field public static final String MANAGE_DEBUGGING = "android.permission.MANAGE_DEBUGGING";
     field public static final String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
+    field public static final String MANAGE_ONE_TIME_PERMISSION_SESSIONS = "android.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS";
     field public static final String MANAGE_ROLE_HOLDERS = "android.permission.MANAGE_ROLE_HOLDERS";
     field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
     field public static final String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY";
@@ -127,6 +128,7 @@
     field public static final String MODIFY_PARENTAL_CONTROLS = "android.permission.MODIFY_PARENTAL_CONTROLS";
     field public static final String MODIFY_QUIET_MODE = "android.permission.MODIFY_QUIET_MODE";
     field public static final String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE";
+    field public static final String NETWORK_AIRPLANE_MODE = "android.permission.NETWORK_AIRPLANE_MODE";
     field public static final String NETWORK_CARRIER_PROVISIONING = "android.permission.NETWORK_CARRIER_PROVISIONING";
     field public static final String NETWORK_FACTORY = "android.permission.NETWORK_FACTORY";
     field public static final String NETWORK_MANAGED_PROVISIONING = "android.permission.NETWORK_MANAGED_PROVISIONING";
@@ -4600,7 +4602,7 @@
     method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
     method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
     method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
-    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
+    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
     method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public boolean shouldAvoidBadWifi();
     method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
     method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
@@ -7247,8 +7249,8 @@
     method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToLuiApp(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void revokeDefaultPermissionsFromLuiApps(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
-    method @RequiresPermission(allOf={android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void startOneTimePermissionSession(@NonNull String, long, int, int);
-    method @RequiresPermission(allOf={android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void stopOneTimePermissionSession(@NonNull String);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, int, int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void stopOneTimePermissionSession(@NonNull String);
   }
 
   public static final class PermissionManager.SplitPermissionInfo {
@@ -7712,7 +7714,9 @@
   public static final class Telephony.Carriers implements android.provider.BaseColumns {
     field public static final String APN_SET_ID = "apn_set_id";
     field public static final int CARRIER_EDITED = 4; // 0x4
+    field @NonNull public static final android.net.Uri DPC_URI;
     field public static final String EDITED_STATUS = "edited";
+    field public static final int INVALID_APN_ID = -1; // 0xffffffff
     field public static final String MAX_CONNECTIONS = "max_conns";
     field public static final String MODEM_PERSIST = "modem_cognitive";
     field public static final String MTU = "mtu";
@@ -9769,6 +9773,7 @@
 
   public class ServiceState implements android.os.Parcelable {
     method @NonNull public android.telephony.ServiceState createLocationInfoSanitizedCopy(boolean);
+    method public void fillInNotifierBundle(@NonNull android.os.Bundle);
     method public int getDataRegistrationState();
     method @Nullable public android.telephony.NetworkRegistrationInfo getNetworkRegistrationInfo(int, int);
     method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoList();
@@ -9777,6 +9782,7 @@
     method public int getNrFrequencyRange();
     method @Nullable public String getOperatorAlphaLongRaw();
     method @Nullable public String getOperatorAlphaShortRaw();
+    method @NonNull public static android.telephony.ServiceState newFromBundle(@NonNull android.os.Bundle);
     field public static final int ROAMING_TYPE_DOMESTIC = 2; // 0x2
     field public static final int ROAMING_TYPE_INTERNATIONAL = 3; // 0x3
     field public static final int ROAMING_TYPE_NOT_ROAMING = 0; // 0x0
@@ -9985,6 +9991,7 @@
   }
 
   public class TelephonyManager {
+    method public int addDevicePolicyOverrideApn(@NonNull android.content.Context, @NonNull android.telephony.data.ApnSetting);
     method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String);
     method public int checkCarrierPrivilegesForPackage(String);
     method public int checkCarrierPrivilegesForPackageAnyPhone(String);
@@ -10013,6 +10020,7 @@
     method @Deprecated public boolean getDataEnabled(int);
     method @Nullable public static android.content.ComponentName getDefaultRespondViaMessageApplication(@NonNull android.content.Context, boolean);
     method @NonNull public static String getDefaultSimCountryIso();
+    method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context);
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDeviceSoftwareVersion(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode();
     method public int getEmergencyNumberDbVersion();
@@ -10059,6 +10067,7 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isTetheringApnRequired();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isVideoCallingEnabled();
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle);
+    method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting);
     method public boolean needsOtaServiceProvisioning();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
diff --git a/api/test-current.txt b/api/test-current.txt
index e7153e6..1c1d794 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -3249,14 +3249,17 @@
   }
 
   public class TelephonyManager {
+    method public int addDevicePolicyOverrideApn(@NonNull android.content.Context, @NonNull android.telephony.data.ApnSetting);
     method public int checkCarrierPrivilegesForPackage(String);
     method public int getCarrierIdListVersion();
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
     method @Nullable public static android.content.ComponentName getDefaultRespondViaMessageApplication(@NonNull android.content.Context, boolean);
+    method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context);
     method public int getEmergencyNumberDbVersion();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag();
     method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getNetworkCountryIso(int);
     method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion();
+    method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
     method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String);
     method public void setCarrierTestOverride(String, String, String, String, String, String, String, String, String);
diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java
index a077745..08216d9 100644
--- a/cmds/input/src/com/android/commands/input/Input.java
+++ b/cmds/input/src/com/android/commands/input/Input.java
@@ -430,6 +430,6 @@
                 + " (Default: touchscreen)");
         out.println("      press (Default: trackball)");
         out.println("      roll <dx> <dy> (Default: trackball)");
-        out.println("      event <DOWN|UP|MOVE> <x> <y> (Default: touchscreen)");
+        out.println("      motionevent <DOWN|UP|MOVE> <x> <y> (Default: touchscreen)");
     }
 }
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 815e3e6..19b9709 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -6691,6 +6691,9 @@
 
     // App is not doing pre-rotation correctly.
     optional bool false_prerotation = 7;
+
+    // App creates GLESv1 context.
+    optional bool gles_1_in_use = 8;
 }
 
 /*
diff --git a/cmds/statsd/src/external/GpuStatsPuller.cpp b/cmds/statsd/src/external/GpuStatsPuller.cpp
index d38b87f..3229ba8 100644
--- a/cmds/statsd/src/external/GpuStatsPuller.cpp
+++ b/cmds/statsd/src/external/GpuStatsPuller.cpp
@@ -103,6 +103,7 @@
         }
         if (!event->write(info.cpuVulkanInUse)) return false;
         if (!event->write(info.falsePrerotation)) return false;
+        if (!event->write(info.gles1InUse)) return false;
         event->init();
         data->emplace_back(event);
     }
diff --git a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
index 6abdfa3..ae92705 100644
--- a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
+++ b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
@@ -58,8 +58,9 @@
 static const int32_t GLES_VERSION                 = 3;
 static const bool CPU_VULKAN_IN_USE               = true;
 static const bool FALSE_PREROTATION               = true;
+static const bool GLES_1_IN_USE                   = true;
 static const size_t NUMBER_OF_VALUES_GLOBAL       = 13;
-static const size_t NUMBER_OF_VALUES_APP          = 7;
+static const size_t NUMBER_OF_VALUES_APP          = 8;
 // clang-format on
 
 class MockGpuStatsPuller : public GpuStatsPuller {
@@ -153,6 +154,7 @@
     EXPECT_TRUE(event->write(int64VectorToProtoByteString(angleDriverLoadingTime)));
     EXPECT_TRUE(event->write(CPU_VULKAN_IN_USE));
     EXPECT_TRUE(event->write(FALSE_PREROTATION));
+    EXPECT_TRUE(event->write(GLES_1_IN_USE));
     event->init();
     inData.emplace_back(event);
     MockGpuStatsPuller mockPuller(android::util::GPU_STATS_APP_INFO, &inData);
@@ -172,6 +174,7 @@
               outData[0]->getValues()[4].mValue.str_value);
     EXPECT_EQ(CPU_VULKAN_IN_USE, outData[0]->getValues()[5].mValue.int_value);
     EXPECT_EQ(FALSE_PREROTATION, outData[0]->getValues()[6].mValue.int_value);
+    EXPECT_EQ(GLES_1_IN_USE, outData[0]->getValues()[7].mValue.int_value);
 }
 
 }  // namespace statsd
diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt
index 652669c..4d0acb3 100644
--- a/config/boot-image-profile.txt
+++ b/config/boot-image-profile.txt
@@ -14142,7 +14142,6 @@
 HSPLandroid/telephony/ServiceState;->copyFrom(Landroid/telephony/ServiceState;)V
 HSPLandroid/telephony/ServiceState;->describeContents()I
 HSPLandroid/telephony/ServiceState;->equals(Ljava/lang/Object;)Z
-HSPLandroid/telephony/ServiceState;->fillInNotifierBundle(Landroid/os/Bundle;)V
 HSPLandroid/telephony/ServiceState;->getCdmaDefaultRoamingIndicator()I
 HSPLandroid/telephony/ServiceState;->getCdmaEriIconIndex()I
 HSPLandroid/telephony/ServiceState;->getCdmaEriIconMode()I
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 08f8734..a4f6f57 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3659,7 +3659,7 @@
                     r.activity, Looper.myLooper());
         }
         r.activity.onGetDirectActions(cancellationSignal, (actions) -> {
-            Preconditions.checkNotNull(actions);
+            Objects.requireNonNull(actions);
             Preconditions.checkCollectionElementsNotNull(actions, "actions");
             if (!actions.isEmpty()) {
                 final int actionCount = actions.size();
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 86a5c76..c942a46 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -51,6 +51,7 @@
 import android.util.ArraySet;
 import android.util.LongSparseArray;
 import android.util.LongSparseLongArray;
+import android.util.Pools;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
@@ -1159,8 +1160,6 @@
     })
     private @interface ShouldCollectNoteOp {}
 
-    // Warning: If an permission is added here it also has to be added to
-    // com.android.packageinstaller.permission.utils.EventLogger
     private static final int[] RUNTIME_AND_APPOP_PERMISSIONS_OPS = {
             // RUNTIME PERMISSIONS
             // Contacts
@@ -1220,7 +1219,8 @@
             OP_START_FOREGROUND,
             OP_SMS_FINANCIAL_TRANSACTIONS,
             OP_MANAGE_IPSEC_TUNNELS,
-            OP_INSTANT_APP_START_FOREGROUND
+            OP_INSTANT_APP_START_FOREGROUND,
+            OP_MANAGE_EXTERNAL_STORAGE,
     };
 
     /**
@@ -1624,7 +1624,7 @@
             null, // no direct permission for OP_READ_DEVICE_IDENTIFIERS
             Manifest.permission.ACCESS_MEDIA_LOCATION,
             null, // no permission for OP_QUERY_ALL_PACKAGES
-            null, // no permission for OP_MANAGE_EXTERNAL_STORAGE
+            Manifest.permission.MANAGE_EXTERNAL_STORAGE,
     };
 
     /**
@@ -2045,7 +2045,7 @@
      * transaction. Not set if this thread is currently not executing a two way binder transaction.
      *
      * @see #startNotedAppOpsCollection
-     * @see #markAppOpNoted
+     * @see #getNotedOpCollectionMode
      */
     private static final ThreadLocal<Integer> sBinderThreadCallingUid = new ThreadLocal<>();
 
@@ -2053,7 +2053,8 @@
      * If a thread is currently executing a two-way binder transaction, this stores the op-codes of
      * the app-ops that were noted during this transaction.
      *
-     * @see #markAppOpNoted
+     * @see #getNotedOpCollectionMode
+     * @see #collectNotedOpSync
      */
     private static final ThreadLocal<ArrayMap<String, long[]>> sAppOpsNotedInThisBinderTransaction =
             new ThreadLocal<>();
@@ -2341,15 +2342,31 @@
      */
     @TestApi
     @SystemApi
-    @Immutable
-    @DataClass(genHiddenConstructor = true)
+    // @DataClass(genHiddenConstructor = true, genHiddenCopyConstructor = true)
+    // genHiddenCopyConstructor does not work for @hide @SystemApi classes
     public static final class OpEventProxyInfo implements Parcelable {
         /** UID of the proxy app that noted the op */
-        private final @IntRange(from = 0) int mUid;
+        private @IntRange(from = 0) int mUid;
         /** Package of the proxy that noted the op */
-        private final @Nullable String mPackageName;
+        private @Nullable String mPackageName;
         /** ID of the feature of the proxy that noted the op */
-        private final @Nullable String mFeatureId;
+        private @Nullable String mFeatureId;
+
+        /**
+         * Reinit existing object with new state.
+         *
+         * @param uid UID of the proxy app that noted the op
+         * @param packageName Package of the proxy that noted the op
+         * @param featureId ID of the feature of the proxy that noted the op
+         *
+         * @hide
+         */
+        public void reinit(@IntRange(from = 0) int uid, @Nullable String packageName,
+                @Nullable String featureId) {
+            mUid = Preconditions.checkArgumentNonnegative(uid);
+            mPackageName = packageName;
+            mFeatureId = featureId;
+        }
 
 
 
@@ -2393,6 +2410,18 @@
         }
 
         /**
+         * Copy constructor
+         *
+         * @hide
+         */
+        @DataClass.Generated.Member
+        public OpEventProxyInfo(@NonNull OpEventProxyInfo orig) {
+            mUid = orig.mUid;
+            mPackageName = orig.mPackageName;
+            mFeatureId = orig.mFeatureId;
+        }
+
+        /**
          * UID of the proxy app that noted the op
          */
         @DataClass.Generated.Member
@@ -2471,14 +2500,15 @@
             }
         };
 
+        /*
         @DataClass.Generated(
-                time = 1576194071700L,
+                time = 1576814974615L,
                 codegenVersion = "1.0.14",
                 sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
-                inputSignatures = "private final @android.annotation.IntRange(from=0L) int mUid\nprivate final @android.annotation.Nullable java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nclass OpEventProxyInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
+                inputSignatures = "private @android.annotation.IntRange(from=0L) int mUid\nprivate @android.annotation.Nullable java.lang.String mPackageName\nprivate @android.annotation.Nullable java.lang.String mFeatureId\npublic  void reinit(int,java.lang.String,java.lang.String)\nclass OpEventProxyInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genHiddenCopyConstructor=true)")
         @Deprecated
         private void __metadata() {}
-
+        */
 
         //@formatter:on
         // End of generated code
@@ -2490,15 +2520,48 @@
      *
      * @hide
      */
-    @Immutable
     //@DataClass codegen verifier is broken
     public static final class NoteOpEvent implements Parcelable {
         /** Time of noteOp event */
-        public final @IntRange(from = 0) long noteTime;
+        private @IntRange(from = 0) long mNoteTime;
         /** The duration of this event (in case this is a startOp event, -1 otherwise). */
-        public final @IntRange(from = -1) long duration;
+        private @IntRange(from = -1) long mDuration;
         /** Proxy information of the noteOp event */
-        public final @Nullable OpEventProxyInfo proxy;
+        private @Nullable OpEventProxyInfo mProxy;
+
+        /**
+         * Reinit existing object with new state.
+         *
+         * @param noteTime Time of noteOp event
+         * @param duration The duration of this event (in case this is a startOp event,
+         *                 -1 otherwise).
+         * @param proxy Proxy information of the noteOp event
+         * @param proxyPool  The pool to release previous {@link OpEventProxyInfo} to
+         */
+        public void reinit(@IntRange(from = 0) long noteTime,
+                @IntRange(from = -1) long duration,
+                @Nullable OpEventProxyInfo proxy,
+                @NonNull Pools.Pool<OpEventProxyInfo> proxyPool) {
+            mNoteTime = Preconditions.checkArgumentNonnegative(noteTime);
+            mDuration = Preconditions.checkArgumentInRange(duration, -1L, Long.MAX_VALUE,
+                    "duration");
+
+            if (mProxy != null) {
+                proxyPool.release(mProxy);
+            }
+            mProxy = proxy;
+        }
+
+        /**
+         * Copy constructor
+         *
+         * @hide
+         */
+        public NoteOpEvent(@NonNull NoteOpEvent original) {
+            this(original.mNoteTime, original.mDuration,
+                    original.mProxy != null ? new OpEventProxyInfo(original.mProxy) : null);
+        }
+
 
 
         // Code below generated by codegen v1.0.14.
@@ -2529,19 +2592,43 @@
                 @IntRange(from = 0) long noteTime,
                 @IntRange(from = -1) long duration,
                 @Nullable OpEventProxyInfo proxy) {
-            this.noteTime = noteTime;
+            this.mNoteTime = noteTime;
             com.android.internal.util.AnnotationValidations.validate(
-                    IntRange.class, null, noteTime,
+                    IntRange.class, null, mNoteTime,
                     "from", 0);
-            this.duration = duration;
+            this.mDuration = duration;
             com.android.internal.util.AnnotationValidations.validate(
-                    IntRange.class, null, duration,
+                    IntRange.class, null, mDuration,
                     "from", -1);
-            this.proxy = proxy;
+            this.mProxy = proxy;
 
             // onConstructed(); // You can define this method to get a callback
         }
 
+        /**
+         * Time of noteOp event
+         */
+        @DataClass.Generated.Member
+        public @IntRange(from = 0) long getNoteTime() {
+            return mNoteTime;
+        }
+
+        /**
+         * The duration of this event (in case this is a startOp event, -1 otherwise).
+         */
+        @DataClass.Generated.Member
+        public @IntRange(from = -1) long getDuration() {
+            return mDuration;
+        }
+
+        /**
+         * Proxy information of the noteOp event
+         */
+        @DataClass.Generated.Member
+        public @Nullable OpEventProxyInfo getProxy() {
+            return mProxy;
+        }
+
         @Override
         @DataClass.Generated.Member
         public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -2549,11 +2636,11 @@
             // void parcelFieldName(Parcel dest, int flags) { ... }
 
             byte flg = 0;
-            if (proxy != null) flg |= 0x4;
+            if (mProxy != null) flg |= 0x4;
             dest.writeByte(flg);
-            dest.writeLong(noteTime);
-            dest.writeLong(duration);
-            if (proxy != null) dest.writeTypedObject(proxy, flags);
+            dest.writeLong(mNoteTime);
+            dest.writeLong(mDuration);
+            if (mProxy != null) dest.writeTypedObject(mProxy, flags);
         }
 
         @Override
@@ -2568,20 +2655,19 @@
             // static FieldType unparcelFieldName(Parcel in) { ... }
 
             byte flg = in.readByte();
-            long _noteTime = in.readLong();
-            long _duration = in.readLong();
-            OpEventProxyInfo _proxy = (flg & 0x4) == 0 ? null : (OpEventProxyInfo) in.readTypedObject(
-                    OpEventProxyInfo.CREATOR);
+            long noteTime = in.readLong();
+            long duration = in.readLong();
+            OpEventProxyInfo proxy = (flg & 0x4) == 0 ? null : (OpEventProxyInfo) in.readTypedObject(OpEventProxyInfo.CREATOR);
 
-            this.noteTime = _noteTime;
+            this.mNoteTime = noteTime;
             com.android.internal.util.AnnotationValidations.validate(
-                    IntRange.class, null, noteTime,
+                    IntRange.class, null, mNoteTime,
                     "from", 0);
-            this.duration = _duration;
+            this.mDuration = duration;
             com.android.internal.util.AnnotationValidations.validate(
-                    IntRange.class, null, duration,
+                    IntRange.class, null, mDuration,
                     "from", -1);
-            this.proxy = _proxy;
+            this.mProxy = proxy;
 
             // onConstructed(); // You can define this method to get a callback
         }
@@ -2602,10 +2688,10 @@
 
         /*
         @DataClass.Generated(
-                time = 1574809856220L,
+                time = 1576811792274L,
                 codegenVersion = "1.0.14",
                 sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
-                inputSignatures = "public final @android.annotation.IntRange(from=0L) long noteTime\npublic final @android.annotation.IntRange(from=-1) long duration\npublic final @android.annotation.Nullable android.app.NoteOpEventProxyInfo proxy\nclass NoteOpEvent extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass")
+                inputSignatures = "private @android.annotation.IntRange(from=0L) long mNoteTime\nprivate @android.annotation.IntRange(from=-1) long mDuration\nprivate @android.annotation.Nullable android.app.OpEventProxyInfo mProxy\npublic  void reinit(long,long,android.app.OpEventProxyInfo,android.util.Pools.Pool<android.app.OpEventProxyInfo>)\npublic @java.lang.Override java.lang.Object clone()\nclass NoteOpEvent extends java.lang.Object implements [android.os.Parcelable, java.lang.Cloneable]\n@com.android.internal.util.DataClass")
         @Deprecated
         private void __metadata() {}
          */
@@ -2751,7 +2837,7 @@
                 return -1;
             }
 
-            return lastEvent.noteTime;
+            return lastEvent.getNoteTime();
         }
 
         /**
@@ -2847,7 +2933,7 @@
                 return -1;
             }
 
-            return lastEvent.noteTime;
+            return lastEvent.getNoteTime();
         }
 
         /**
@@ -2922,7 +3008,7 @@
                 return -1;
             }
 
-            return lastEvent.duration;
+            return lastEvent.getDuration();
         }
 
         /**
@@ -3000,7 +3086,7 @@
                 return null;
             }
 
-            return lastEvent.proxy;
+            return lastEvent.getProxy();
         }
 
         private static class LongSparseArrayParceling implements
@@ -3304,7 +3390,7 @@
                         toUidState, flags);
 
                 if (lastAccessEvent == null || (lastFeatureAccessEvent != null
-                        && lastFeatureAccessEvent.noteTime > lastAccessEvent.noteTime)) {
+                        && lastFeatureAccessEvent.getNoteTime() > lastAccessEvent.getNoteTime())) {
                     lastAccessEvent = lastFeatureAccessEvent;
                 }
             }
@@ -3335,7 +3421,7 @@
                 return -1;
             }
 
-            return lastEvent.noteTime;
+            return lastEvent.getNoteTime();
         }
 
         /**
@@ -3418,7 +3504,7 @@
                         toUidState, flags);
 
                 if (lastAccessEvent == null || (lastFeatureAccessEvent != null
-                        && lastFeatureAccessEvent.noteTime > lastAccessEvent.noteTime)) {
+                        && lastFeatureAccessEvent.getNoteTime() > lastAccessEvent.getNoteTime())) {
                     lastAccessEvent = lastFeatureAccessEvent;
                 }
             }
@@ -3449,7 +3535,7 @@
                 return -1;
             }
 
-            return lastEvent.noteTime;
+            return lastEvent.getNoteTime();
         }
 
         /**
@@ -3544,7 +3630,7 @@
                 return -1;
             }
 
-            return lastEvent.duration;
+            return lastEvent.getDuration();
         }
 
         /**
@@ -3674,7 +3760,7 @@
                 return null;
             }
 
-            return lastEvent.proxy;
+            return lastEvent.getProxy();
         }
 
 
@@ -5517,8 +5603,8 @@
     @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
     public void getHistoricalOps(@NonNull HistoricalOpsRequest request,
             @NonNull Executor executor, @NonNull Consumer<HistoricalOps> callback) {
-        Preconditions.checkNotNull(executor, "executor cannot be null");
-        Preconditions.checkNotNull(callback, "callback cannot be null");
+        Objects.requireNonNull(executor, "executor cannot be null");
+        Objects.requireNonNull(callback, "callback cannot be null");
         try {
             mService.getHistoricalOps(request.mUid, request.mPackageName, request.mOpNames,
                     request.mBeginTimeMillis, request.mEndTimeMillis, request.mFlags,
@@ -5556,8 +5642,8 @@
     @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
     public void getHistoricalOpsFromDiskRaw(@NonNull HistoricalOpsRequest request,
             @Nullable Executor executor, @NonNull Consumer<HistoricalOps> callback) {
-        Preconditions.checkNotNull(executor, "executor cannot be null");
-        Preconditions.checkNotNull(callback, "callback cannot be null");
+        Objects.requireNonNull(executor, "executor cannot be null");
+        Objects.requireNonNull(callback, "callback cannot be null");
         try {
             mService.getHistoricalOpsFromDiskRaw(request.mUid, request.mPackageName,
                     request.mOpNames, request.mBeginTimeMillis, request.mEndTimeMillis,
@@ -6236,9 +6322,23 @@
     public int noteOpNoThrow(int op, int uid, @Nullable String packageName,
             @Nullable String featureId, @Nullable String message) {
         try {
-            int mode = mService.noteOperation(op, uid, packageName, featureId);
+            int collectionMode = getNotedOpCollectionMode(uid, packageName, op);
+            if (collectionMode == COLLECT_ASYNC) {
+                if (message == null) {
+                    // Set stack trace as default message
+                    message = getFormattedStackTrace();
+                }
+            }
+
+            int mode = mService.noteOperation(op, uid, packageName, featureId,
+                    collectionMode == COLLECT_ASYNC, message);
+
             if (mode == MODE_ALLOWED) {
-                markAppOpNoted(uid, packageName, op, featureId, message);
+                if (collectionMode == COLLECT_SELF) {
+                    collectNotedOpForSelf(op, featureId);
+                } else if (collectionMode == COLLECT_SYNC) {
+                    collectNotedOpSync(op, featureId);
+                }
             }
 
             return mode;
@@ -6382,14 +6482,27 @@
         int myUid = Process.myUid();
 
         try {
+            int collectionMode = getNotedOpCollectionMode(proxiedUid, proxiedPackageName, op);
+            if (collectionMode == COLLECT_ASYNC) {
+                if (message == null) {
+                    // Set stack trace as default message
+                    message = getFormattedStackTrace();
+                }
+            }
+
             int mode = mService.noteProxyOperation(op, proxiedUid, proxiedPackageName,
                     proxiedFeatureId, myUid, mContext.getOpPackageName(),
-                    mContext.getFeatureId());
-            if (mode == MODE_ALLOWED
-                    // Only collect app-ops when the proxy is trusted
-                    && mContext.checkPermission(Manifest.permission.UPDATE_APP_OPS_STATS, -1, myUid)
-                    == PackageManager.PERMISSION_GRANTED) {
-                markAppOpNoted(proxiedUid, proxiedPackageName, op, proxiedFeatureId, message);
+                    mContext.getFeatureId(), collectionMode == COLLECT_ASYNC, message);
+
+            if (mode == MODE_ALLOWED) {
+                if (collectionMode == COLLECT_SELF) {
+                    collectNotedOpForSelf(op, proxiedFeatureId);
+                } else if (collectionMode == COLLECT_SYNC
+                        // Only collect app-ops when the proxy is trusted
+                        && mContext.checkPermission(Manifest.permission.UPDATE_APP_OPS_STATS, -1,
+                        myUid) == PackageManager.PERMISSION_GRANTED) {
+                    collectNotedOpSync(op, proxiedFeatureId);
+                }
             }
 
             return mode;
@@ -6679,10 +6792,23 @@
     public int startOpNoThrow(int op, int uid, @NonNull String packageName,
             boolean startIfModeDefault, @Nullable String featureId, @Nullable String message) {
         try {
+            int collectionMode = getNotedOpCollectionMode(uid, packageName, op);
+            if (collectionMode == COLLECT_ASYNC) {
+                if (message == null) {
+                    // Set stack trace as default message
+                    message = getFormattedStackTrace();
+                }
+            }
+
             int mode = mService.startOperation(getClientId(), op, uid, packageName,
-                    featureId, startIfModeDefault);
+                    featureId, startIfModeDefault, collectionMode == COLLECT_ASYNC, message);
+
             if (mode == MODE_ALLOWED) {
-                markAppOpNoted(uid, packageName, op, featureId, message);
+                if (collectionMode == COLLECT_SELF) {
+                    collectNotedOpForSelf(op, featureId);
+                } else if (collectionMode == COLLECT_SYNC) {
+                    collectNotedOpSync(op, featureId);
+                }
             }
 
             return mode;
@@ -6846,85 +6972,106 @@
     }
 
     /**
-     * Mark an app-op as noted
+     * Collect a noted op for the current process.
+     *
+     * @param op The noted op
+     * @param featureId The feature the op is noted for
      */
-    private void markAppOpNoted(int uid, @Nullable String packageName, int code,
-            @Nullable String featureId, @Nullable String message) {
+    private void collectNotedOpForSelf(int op, @Nullable String featureId) {
+        synchronized (sLock) {
+            if (sNotedAppOpsCollector != null) {
+                sNotedAppOpsCollector.onSelfNoted(new SyncNotedAppOp(op, featureId));
+            }
+        }
+    }
+
+    /**
+     * Collect a noted op when inside of a two-way binder call.
+     *
+     * <p> Delivered to caller via {@link #prefixParcelWithAppOpsIfNeeded}
+     *
+     * @param op The noted op
+     * @param featureId The feature the op is noted for
+     */
+    private void collectNotedOpSync(int op, @Nullable String featureId) {
+        // If this is inside of a two-way binder call:
+        // We are inside of a two-way binder call. Delivered to caller via
+        // {@link #prefixParcelWithAppOpsIfNeeded}
+        ArrayMap<String, long[]> appOpsNoted = sAppOpsNotedInThisBinderTransaction.get();
+        if (appOpsNoted == null) {
+            appOpsNoted = new ArrayMap<>(1);
+            sAppOpsNotedInThisBinderTransaction.set(appOpsNoted);
+        }
+
+        long[] appOpsNotedForFeature = appOpsNoted.get(featureId);
+        if (appOpsNotedForFeature == null) {
+            appOpsNotedForFeature = new long[2];
+            appOpsNoted.put(featureId, appOpsNotedForFeature);
+        }
+
+        if (op < 64) {
+            appOpsNotedForFeature[0] |= 1L << op;
+        } else {
+            appOpsNotedForFeature[1] |= 1L << (op - 64);
+        }
+    }
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+            DONT_COLLECT,
+            COLLECT_SELF,
+            COLLECT_SYNC,
+            COLLECT_ASYNC
+    })
+    private @interface NotedOpCollectionMode {}
+    private static final int DONT_COLLECT = 0;
+    private static final int COLLECT_SELF = 1;
+    private static final int COLLECT_SYNC = 2;
+    private static final int COLLECT_ASYNC = 3;
+
+    /**
+     * Mark an app-op as noted.
+     */
+    private @NotedOpCollectionMode int getNotedOpCollectionMode(int uid,
+            @Nullable String packageName, int op) {
         if (packageName == null) {
             packageName = "android";
         }
 
         // check it the appops needs to be collected and cache result
-        if (sAppOpsToNote[code] == SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED) {
+        if (sAppOpsToNote[op] == SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED) {
             boolean shouldCollectNotes;
             try {
-                shouldCollectNotes = mService.shouldCollectNotes(code);
+                shouldCollectNotes = mService.shouldCollectNotes(op);
             } catch (RemoteException e) {
-                return;
+                return DONT_COLLECT;
             }
 
             if (shouldCollectNotes) {
-                sAppOpsToNote[code] = SHOULD_COLLECT_NOTE_OP;
+                sAppOpsToNote[op] = SHOULD_COLLECT_NOTE_OP;
             } else {
-                sAppOpsToNote[code] = SHOULD_NOT_COLLECT_NOTE_OP;
+                sAppOpsToNote[op] = SHOULD_NOT_COLLECT_NOTE_OP;
             }
         }
 
-        if (sAppOpsToNote[code] != SHOULD_COLLECT_NOTE_OP) {
-            return;
+        if (sAppOpsToNote[op] != SHOULD_COLLECT_NOTE_OP) {
+            return DONT_COLLECT;
+        }
+
+        synchronized (sLock) {
+            if (uid == Process.myUid()
+                    && packageName.equals(ActivityThread.currentOpPackageName())) {
+                return COLLECT_SELF;
+            }
         }
 
         Integer binderUid = sBinderThreadCallingUid.get();
 
-        synchronized (sLock) {
-            if (sNotedAppOpsCollector != null && uid == Process.myUid() && packageName.equals(
-                    ActivityThread.currentOpPackageName())) {
-                // This app is noting an app-op for itself. Deliver immediately.
-                sNotedAppOpsCollector.onSelfNoted(new SyncNotedAppOp(code, featureId));
-
-                return;
-            }
-        }
-
         if (binderUid != null && binderUid == uid) {
-            // If this is inside of a two-way binder call: Delivered to caller via
-            // {@link #prefixParcelWithAppOpsIfNeeded}
-            // We are inside of a two-way binder call. Delivered to caller via
-            // {@link #prefixParcelWithAppOpsIfNeeded}
-            ArrayMap<String, long[]> appOpsNoted = sAppOpsNotedInThisBinderTransaction.get();
-            if (appOpsNoted == null) {
-                appOpsNoted = new ArrayMap<>(1);
-                sAppOpsNotedInThisBinderTransaction.set(appOpsNoted);
-            }
-
-            long[] appOpsNotedForFeature = appOpsNoted.get(featureId);
-            if (appOpsNotedForFeature == null) {
-                appOpsNotedForFeature = new long[2];
-                appOpsNoted.put(featureId, appOpsNotedForFeature);
-            }
-
-            if (code < 64) {
-                appOpsNotedForFeature[0] |= 1L << code;
-            } else {
-                appOpsNotedForFeature[1] |= 1L << (code - 64);
-            }
+            return COLLECT_SYNC;
         } else {
-            // Cannot deliver the note synchronous: Hence send it to the system server to
-            // notify the noted process.
-            if (message == null) {
-                // Default message is a stack trace
-                message = getFormattedStackTrace();
-            }
-
-            long token = Binder.clearCallingIdentity();
-            try {
-                mService.noteAsyncOp(mContext.getOpPackageName(), uid, packageName, code,
-                        featureId, message);
-            } catch (RemoteException e) {
-                e.rethrowFromSystemServer();
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
+            return COLLECT_ASYNC;
         }
     }
 
@@ -7062,7 +7209,7 @@
         private final IAppOpsAsyncNotedCallback mAsyncCb = new IAppOpsAsyncNotedCallback.Stub() {
             @Override
             public void opNoted(AsyncNotedAppOp op) {
-                Preconditions.checkNotNull(op);
+                Objects.requireNonNull(op);
 
                 getAsyncNotedExecutor().execute(() -> onAsyncNoted(op));
             }
@@ -7331,7 +7478,8 @@
                 final long key = makeKey(uidState, flag);
 
                 NoteOpEvent event = events.get(key);
-                if (lastEvent == null || event != null && event.noteTime > lastEvent.noteTime) {
+                if (lastEvent == null
+                        || event != null && event.getNoteTime() > lastEvent.getNoteTime()) {
                     lastEvent = event;
                 }
             }
diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java
index bd7ef2a..099037c 100644
--- a/core/java/android/app/AppOpsManagerInternal.java
+++ b/core/java/android/app/AppOpsManagerInternal.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.util.SparseIntArray;
 
+import com.android.internal.util.function.HexFunction;
 import com.android.internal.util.function.QuadFunction;
 
 /**
@@ -63,12 +64,16 @@
          * @param uid The UID for which to note.
          * @param packageName The package for which to note. {@code null} for system package.
          * @param featureId Id of the feature in the package
+         * @param shouldCollectAsyncNotedOp If an {@link AsyncNotedAppOp} should be collected
+         * @param message The message in the async noted op
          * @param superImpl The super implementation.
          * @return The app op note result.
          */
         int noteOperation(int code, int uid, @Nullable String packageName,
-                @Nullable String featureId,
-                @NonNull QuadFunction<Integer, Integer, String, String, Integer> superImpl);
+                @Nullable String featureId, boolean shouldCollectAsyncNotedOp,
+                @Nullable String message,
+                @NonNull HexFunction<Integer, Integer, String, String, Boolean, String, Integer>
+                        superImpl);
     }
 
     /**
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 7f26565..1c6a561 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -100,7 +100,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.SomeArgs;
-import com.android.internal.util.Preconditions;
 import com.android.internal.util.UserIcons;
 
 import dalvik.system.VMRuntime;
@@ -2149,7 +2148,7 @@
             } else if (vol.isPrimaryPhysical()) {
                 volumeUuid = StorageManager.UUID_PRIMARY_PHYSICAL;
             } else {
-                volumeUuid = Preconditions.checkNotNull(vol.fsUuid);
+                volumeUuid = Objects.requireNonNull(vol.fsUuid);
             }
 
             return mPM.movePackage(packageName, volumeUuid);
@@ -2259,7 +2258,7 @@
             } else if (vol.isPrimaryPhysical()) {
                 volumeUuid = StorageManager.UUID_PRIMARY_PHYSICAL;
             } else {
-                volumeUuid = Preconditions.checkNotNull(vol.fsUuid);
+                volumeUuid = Objects.requireNonNull(vol.fsUuid);
             }
 
             return mPM.movePrimaryStorage(volumeUuid);
@@ -2661,8 +2660,8 @@
     /** @hide */
     @Override
     public KeySet getKeySetByAlias(String packageName, String alias) {
-        Preconditions.checkNotNull(packageName);
-        Preconditions.checkNotNull(alias);
+        Objects.requireNonNull(packageName);
+        Objects.requireNonNull(alias);
         try {
             return mPM.getKeySetByAlias(packageName, alias);
         } catch (RemoteException e) {
@@ -2673,7 +2672,7 @@
     /** @hide */
     @Override
     public KeySet getSigningKeySet(String packageName) {
-        Preconditions.checkNotNull(packageName);
+        Objects.requireNonNull(packageName);
         try {
             return mPM.getSigningKeySet(packageName);
         } catch (RemoteException e) {
@@ -2684,8 +2683,8 @@
     /** @hide */
     @Override
     public boolean isSignedBy(String packageName, KeySet ks) {
-        Preconditions.checkNotNull(packageName);
-        Preconditions.checkNotNull(ks);
+        Objects.requireNonNull(packageName);
+        Objects.requireNonNull(ks);
         try {
             return mPM.isPackageSignedByKeySet(packageName, ks);
         } catch (RemoteException e) {
@@ -2696,8 +2695,8 @@
     /** @hide */
     @Override
     public boolean isSignedByExactly(String packageName, KeySet ks) {
-        Preconditions.checkNotNull(packageName);
-        Preconditions.checkNotNull(ks);
+        Objects.requireNonNull(packageName);
+        Objects.requireNonNull(ks);
         try {
             return mPM.isPackageSignedByKeySetExactly(packageName, ks);
         } catch (RemoteException e) {
diff --git a/core/java/android/app/AsyncNotedAppOp.java b/core/java/android/app/AsyncNotedAppOp.java
index 0e1f921..c3ef3ad 100644
--- a/core/java/android/app/AsyncNotedAppOp.java
+++ b/core/java/android/app/AsyncNotedAppOp.java
@@ -45,12 +45,6 @@
     /** Uid that noted the op */
     private final @IntRange(from = 0) int mNotingUid;
 
-    /**
-     * Package that noted the op. {@code null} if the package name that noted the op could be not
-     * be determined (e.g. when the op is noted from native code).
-     */
-    private final @Nullable String mNotingPackageName;
-
     /** {@link android.content.Context#createFeatureContext Feature} in the app */
     private final @Nullable String mFeatureId;
 
@@ -69,7 +63,7 @@
 
 
 
-    // Code below generated by codegen v1.0.9.
+    // Code below generated by codegen v1.0.14.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -89,9 +83,6 @@
      *   Op that was noted
      * @param notingUid
      *   Uid that noted the op
-     * @param notingPackageName
-     *   Package that noted the op. {@code null} if the package name that noted the op could be not
-     *   be determined (e.g. when the op is noted from native code).
      * @param featureId
      *   {@link android.content.Context#createFeatureContext Feature} in the app
      * @param message
@@ -104,7 +95,6 @@
     public AsyncNotedAppOp(
             @IntRange(from = 0, to = AppOpsManager._NUM_OP - 1) int opCode,
             @IntRange(from = 0) int notingUid,
-            @Nullable String notingPackageName,
             @Nullable String featureId,
             @NonNull String message,
             @IntRange(from = 0) long time) {
@@ -117,7 +107,6 @@
         com.android.internal.util.AnnotationValidations.validate(
                 IntRange.class, null, mNotingUid,
                 "from", 0);
-        this.mNotingPackageName = notingPackageName;
         this.mFeatureId = featureId;
         this.mMessage = message;
         com.android.internal.util.AnnotationValidations.validate(
@@ -139,15 +128,6 @@
     }
 
     /**
-     * Package that noted the op. {@code null} if the package name that noted the op could be not
-     * be determined (e.g. when the op is noted from native code).
-     */
-    @DataClass.Generated.Member
-    public @Nullable String getNotingPackageName() {
-        return mNotingPackageName;
-    }
-
-    /**
      * {@link android.content.Context#createFeatureContext Feature} in the app
      */
     @DataClass.Generated.Member
@@ -186,7 +166,6 @@
         return true
                 && mOpCode == that.mOpCode
                 && mNotingUid == that.mNotingUid
-                && java.util.Objects.equals(mNotingPackageName, that.mNotingPackageName)
                 && java.util.Objects.equals(mFeatureId, that.mFeatureId)
                 && java.util.Objects.equals(mMessage, that.mMessage)
                 && mTime == that.mTime;
@@ -201,7 +180,6 @@
         int _hash = 1;
         _hash = 31 * _hash + mOpCode;
         _hash = 31 * _hash + mNotingUid;
-        _hash = 31 * _hash + java.util.Objects.hashCode(mNotingPackageName);
         _hash = 31 * _hash + java.util.Objects.hashCode(mFeatureId);
         _hash = 31 * _hash + java.util.Objects.hashCode(mMessage);
         _hash = 31 * _hash + Long.hashCode(mTime);
@@ -215,12 +193,10 @@
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
         byte flg = 0;
-        if (mNotingPackageName != null) flg |= 0x4;
-        if (mFeatureId != null) flg |= 0x8;
+        if (mFeatureId != null) flg |= 0x4;
         dest.writeByte(flg);
         dest.writeInt(mOpCode);
         dest.writeInt(mNotingUid);
-        if (mNotingPackageName != null) dest.writeString(mNotingPackageName);
         if (mFeatureId != null) dest.writeString(mFeatureId);
         dest.writeString(mMessage);
         dest.writeLong(mTime);
@@ -240,8 +216,7 @@
         byte flg = in.readByte();
         int opCode = in.readInt();
         int notingUid = in.readInt();
-        String notingPackageName = (flg & 0x4) == 0 ? null : in.readString();
-        String featureId = (flg & 0x8) == 0 ? null : in.readString();
+        String featureId = (flg & 0x4) == 0 ? null : in.readString();
         String message = in.readString();
         long time = in.readLong();
 
@@ -254,7 +229,6 @@
         com.android.internal.util.AnnotationValidations.validate(
                 IntRange.class, null, mNotingUid,
                 "from", 0);
-        this.mNotingPackageName = notingPackageName;
         this.mFeatureId = featureId;
         this.mMessage = message;
         com.android.internal.util.AnnotationValidations.validate(
@@ -282,11 +256,15 @@
     };
 
     @DataClass.Generated(
-            time = 1571327470155L,
-            codegenVersion = "1.0.9",
+            time = 1576864422226L,
+            codegenVersion = "1.0.14",
             sourceFile = "frameworks/base/core/java/android/app/AsyncNotedAppOp.java",
-            inputSignatures = "private final @android.annotation.IntRange(from=0L, to=92L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mNotingPackageName\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.IntRange(from=0L) long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
+            inputSignatures = "private final @android.annotation.IntRange(from=0L, to=92L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.IntRange(from=0L) long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
     @Deprecated
     private void __metadata() {}
 
+
+    //@formatter:on
+    // End of generated code
+
 }
diff --git a/core/java/android/app/AuthenticationRequiredException.java b/core/java/android/app/AuthenticationRequiredException.java
index 0d87336..847d2c4 100644
--- a/core/java/android/app/AuthenticationRequiredException.java
+++ b/core/java/android/app/AuthenticationRequiredException.java
@@ -21,7 +21,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
 
 /**
  * Specialization of {@link SecurityException} that is thrown when authentication is needed from the
@@ -60,7 +60,7 @@
      */
     public AuthenticationRequiredException(Throwable cause, PendingIntent userAction) {
         super(cause.getMessage());
-        mUserAction = Preconditions.checkNotNull(userAction);
+        mUserAction = Objects.requireNonNull(userAction);
     }
 
     /**
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index bd87fcd..cd84310 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2794,7 +2794,7 @@
 
         public ApplicationContentResolver(Context context, ActivityThread mainThread) {
             super(context);
-            mMainThread = Preconditions.checkNotNull(mainThread);
+            mMainThread = Objects.requireNonNull(mainThread);
         }
 
         @Override
diff --git a/core/java/android/app/DirectAction.java b/core/java/android/app/DirectAction.java
index ef3627b..0268f7c 100644
--- a/core/java/android/app/DirectAction.java
+++ b/core/java/android/app/DirectAction.java
@@ -172,7 +172,7 @@
          *     current application state.
          */
         public Builder(@NonNull String id) {
-            Preconditions.checkNotNull(id);
+            Objects.requireNonNull(id);
             mId = id;
         }
 
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 31c73b9..ca3d0d7 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -198,6 +198,7 @@
 import com.android.internal.util.Preconditions;
 
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * Manages all of the system services that can be returned by {@link Context#getSystemService}.
@@ -1429,8 +1430,8 @@
             @NonNull StaticServiceProducerWithBinder<TServiceClass> serviceProducer) {
         ensureInitializing("registerStaticService");
         Preconditions.checkStringNotEmpty(serviceName);
-        Preconditions.checkNotNull(serviceWrapperClass);
-        Preconditions.checkNotNull(serviceProducer);
+        Objects.requireNonNull(serviceWrapperClass);
+        Objects.requireNonNull(serviceProducer);
 
         registerService(serviceName, serviceWrapperClass,
                 new StaticServiceFetcher<TServiceClass>() {
@@ -1453,8 +1454,8 @@
             @NonNull StaticServiceProducerWithoutBinder<TServiceClass> serviceProducer) {
         ensureInitializing("registerStaticService");
         Preconditions.checkStringNotEmpty(serviceName);
-        Preconditions.checkNotNull(serviceWrapperClass);
-        Preconditions.checkNotNull(serviceProducer);
+        Objects.requireNonNull(serviceWrapperClass);
+        Objects.requireNonNull(serviceProducer);
 
         registerService(serviceName, serviceWrapperClass,
                 new StaticServiceFetcher<TServiceClass>() {
@@ -1486,8 +1487,8 @@
             @NonNull ContextAwareServiceProducerWithBinder<TServiceClass> serviceProducer) {
         ensureInitializing("registerContextAwareService");
         Preconditions.checkStringNotEmpty(serviceName);
-        Preconditions.checkNotNull(serviceWrapperClass);
-        Preconditions.checkNotNull(serviceProducer);
+        Objects.requireNonNull(serviceWrapperClass);
+        Objects.requireNonNull(serviceProducer);
 
         registerService(serviceName, serviceWrapperClass,
                 new CachedServiceFetcher<TServiceClass>() {
@@ -1514,8 +1515,8 @@
             @NonNull ContextAwareServiceProducerWithoutBinder<TServiceClass> serviceProducer) {
         ensureInitializing("registerContextAwareService");
         Preconditions.checkStringNotEmpty(serviceName);
-        Preconditions.checkNotNull(serviceWrapperClass);
-        Preconditions.checkNotNull(serviceProducer);
+        Objects.requireNonNull(serviceWrapperClass);
+        Objects.requireNonNull(serviceProducer);
 
         registerService(serviceName, serviceWrapperClass,
                 new CachedServiceFetcher<TServiceClass>() {
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index b37120f..c262ec2 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -44,6 +44,7 @@
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Objects;
 import java.util.concurrent.Executor;
 
 /**
@@ -1129,8 +1130,8 @@
      */
     public boolean registerOnDestroyedCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull Runnable callback) {
-        Preconditions.checkNotNull(executor);
-        Preconditions.checkNotNull(callback);
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
         if (isDestroyed()) {
             Log.w(TAG, "Cannot interact with a destroyed voice interactor");
             return false;
@@ -1146,7 +1147,7 @@
      * @return whether the callback was unregistered.
      */
     public boolean unregisterOnDestroyedCallback(@NonNull Runnable callback) {
-        Preconditions.checkNotNull(callback);
+        Objects.requireNonNull(callback);
         if (isDestroyed()) {
             Log.w(TAG, "Cannot interact with a destroyed voice interactor");
             return false;
diff --git a/core/java/android/app/admin/DevicePolicyEventLogger.java b/core/java/android/app/admin/DevicePolicyEventLogger.java
index 95a7973..4c0e176 100644
--- a/core/java/android/app/admin/DevicePolicyEventLogger.java
+++ b/core/java/android/app/admin/DevicePolicyEventLogger.java
@@ -25,6 +25,7 @@
 import com.android.internal.util.Preconditions;
 
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * A wrapper for logging managed device events using {@link StatsLog}.
@@ -136,7 +137,7 @@
      * in that order.
      */
     public DevicePolicyEventLogger setStrings(String value, String[] values) {
-        Preconditions.checkNotNull(values, "values parameter cannot be null");
+        Objects.requireNonNull(values, "values parameter cannot be null");
         mStringArrayValue = new String[values.length + 1];
         mStringArrayValue[0] = value;
         System.arraycopy(values, 0, mStringArrayValue, 1, values.length);
@@ -150,7 +151,7 @@
      * and <code>values</code>, in that order.
      */
     public DevicePolicyEventLogger setStrings(String value1, String value2, String[] values) {
-        Preconditions.checkNotNull(values, "values parameter cannot be null");
+        Objects.requireNonNull(values, "values parameter cannot be null");
         mStringArrayValue = new String[values.length + 2];
         mStringArrayValue[0] = value1;
         mStringArrayValue[1] = value2;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index acdf919..c9060c4 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -115,6 +115,7 @@
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
@@ -4263,7 +4264,7 @@
      *            {@link #WIPE_SILENTLY} is set.
      */
     public void wipeData(int flags, @NonNull CharSequence reason) {
-        Preconditions.checkNotNull(reason, "reason string is null");
+        Objects.requireNonNull(reason, "reason string is null");
         Preconditions.checkStringNotEmpty(reason, "reason string is empty");
         Preconditions.checkArgument((flags & WIPE_SILENTLY) == 0, "WIPE_SILENTLY cannot be set");
         wipeDataInternal(flags, reason.toString());
@@ -8483,14 +8484,16 @@
     }
 
     /**
-     * Called by device owner to set the system wall clock time. This only takes effect if called
-     * when {@link android.provider.Settings.Global#AUTO_TIME} is 0, otherwise {@code false} will be
-     * returned.
+     * Called by a device owner or a profile owner of an organization-owned managed
+     * profile to set the system wall clock time. This only takes effect if called when
+     * {@link android.provider.Settings.Global#AUTO_TIME} is 0, otherwise {@code false}
+     * will be returned.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with
      * @param millis time in milliseconds since the Epoch
      * @return {@code true} if set time succeeded, {@code false} otherwise.
-     * @throws SecurityException if {@code admin} is not a device owner.
+     * @throws SecurityException if {@code admin} is not a device owner or a profile owner
+     * of an organization-owned managed profile.
      */
     public boolean setTime(@NonNull ComponentName admin, long millis) {
         throwIfParentInstance("setTime");
@@ -8505,16 +8508,18 @@
     }
 
     /**
-     * Called by device owner to set the system's persistent default time zone. This only takes
-     * effect if called when {@link android.provider.Settings.Global#AUTO_TIME_ZONE} is 0, otherwise
-     * {@code false} will be returned.
+     * Called by a device owner or a profile owner of an organization-owned managed
+     * profile to set the system's persistent default time zone. This only takes
+     * effect if called when {@link android.provider.Settings.Global#AUTO_TIME_ZONE}
+     * is 0, otherwise {@code false} will be returned.
      *
      * @see android.app.AlarmManager#setTimeZone(String)
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with
      * @param timeZone one of the Olson ids from the list returned by
      *     {@link java.util.TimeZone#getAvailableIDs}
      * @return {@code true} if set timezone succeeded, {@code false} otherwise.
-     * @throws SecurityException if {@code admin} is not a device owner.
+     * @throws SecurityException if {@code admin} is not a device owner or a profile owner
+     * of an organization-owned managed profile.
      */
     public boolean setTimeZone(@NonNull ComponentName admin, String timeZone) {
         throwIfParentInstance("setTimeZone");
@@ -10430,8 +10435,8 @@
             @NonNull String packageName, @NonNull @CallbackExecutor Executor executor,
             @NonNull OnClearApplicationUserDataListener listener) {
         throwIfParentInstance("clearAppData");
-        Preconditions.checkNotNull(executor);
-        Preconditions.checkNotNull(listener);
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(listener);
         try {
             mService.clearApplicationUserData(admin, packageName,
                     new IPackageDataObserver.Stub() {
@@ -10881,7 +10886,7 @@
     @WorkerThread public @PrivateDnsModeErrorCodes int setGlobalPrivateDnsModeSpecifiedHost(
             @NonNull ComponentName admin, @NonNull String privateDnsHost) {
         throwIfParentInstance("setGlobalPrivateDnsModeSpecifiedHost");
-        Preconditions.checkNotNull(privateDnsHost, "dns resolver is null");
+        Objects.requireNonNull(privateDnsHost, "dns resolver is null");
 
         if (mService == null) {
             return PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 80c5b17..22d8c87 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -41,6 +41,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * <p>This API automatically creates assist data from the platform's
@@ -1889,7 +1890,7 @@
 
         @Override
         public void setTextIdEntry(@NonNull String entryName) {
-            mNode.mTextIdEntry = Preconditions.checkNotNull(entryName);
+            mNode.mTextIdEntry = Objects.requireNonNull(entryName);
         }
 
         @Override
@@ -1899,7 +1900,7 @@
 
         @Override
         public void setHintIdEntry(@NonNull String entryName) {
-            mNode.mHintIdEntry = Preconditions.checkNotNull(entryName);
+            mNode.mHintIdEntry = Objects.requireNonNull(entryName);
         }
 
         @Override
diff --git a/core/java/android/app/prediction/AppPredictionManager.java b/core/java/android/app/prediction/AppPredictionManager.java
index cb5b7e7..ca22721 100644
--- a/core/java/android/app/prediction/AppPredictionManager.java
+++ b/core/java/android/app/prediction/AppPredictionManager.java
@@ -20,7 +20,7 @@
 import android.annotation.TestApi;
 import android.content.Context;
 
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
 
 /**
  * Class that provides methods to create prediction clients.
@@ -37,7 +37,7 @@
      * @hide
      */
     public AppPredictionManager(Context context) {
-        mContext = Preconditions.checkNotNull(context);
+        mContext = Objects.requireNonNull(context);
     }
 
     /**
diff --git a/core/java/android/app/prediction/AppTarget.java b/core/java/android/app/prediction/AppTarget.java
index 6f21490..14e32b83 100644
--- a/core/java/android/app/prediction/AppTarget.java
+++ b/core/java/android/app/prediction/AppTarget.java
@@ -25,7 +25,7 @@
 import android.os.Parcelable;
 import android.os.UserHandle;
 
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
 
 /**
  * A representation of a launchable target.
@@ -55,9 +55,9 @@
         mId = id;
         mShortcutInfo = null;
 
-        mPackageName = Preconditions.checkNotNull(packageName);
+        mPackageName = Objects.requireNonNull(packageName);
         mClassName = className;
-        mUser = Preconditions.checkNotNull(user);
+        mUser = Objects.requireNonNull(user);
         mRank = 0;
     }
 
@@ -69,7 +69,7 @@
     public AppTarget(@NonNull AppTargetId id, @NonNull ShortcutInfo shortcutInfo,
             @Nullable String className) {
         mId = id;
-        mShortcutInfo = Preconditions.checkNotNull(shortcutInfo);
+        mShortcutInfo = Objects.requireNonNull(shortcutInfo);
 
         mPackageName = mShortcutInfo.getPackage();
         mUser = mShortcutInfo.getUserHandle();
@@ -224,9 +224,9 @@
         @TestApi
         public Builder(@NonNull AppTargetId id, @NonNull String packageName,
                 @NonNull UserHandle user) {
-            mId = Preconditions.checkNotNull(id);
-            mPackageName = Preconditions.checkNotNull(packageName);
-            mUser = Preconditions.checkNotNull(user);
+            mId = Objects.requireNonNull(id);
+            mPackageName = Objects.requireNonNull(packageName);
+            mUser = Objects.requireNonNull(user);
         }
 
         /**
@@ -237,8 +237,8 @@
         @SystemApi
         @TestApi
         public Builder(@NonNull AppTargetId id, @NonNull ShortcutInfo info) {
-            mId = Preconditions.checkNotNull(id);
-            mShortcutInfo = Preconditions.checkNotNull(info);
+            mId = Objects.requireNonNull(id);
+            mShortcutInfo = Objects.requireNonNull(info);
             mPackageName = info.getPackage();
             mUser = info.getUserHandle();
         }
@@ -253,8 +253,8 @@
             if (mPackageName != null) {
                 throw new IllegalArgumentException("Target is already set");
             }
-            mPackageName = Preconditions.checkNotNull(packageName);
-            mUser = Preconditions.checkNotNull(user);
+            mPackageName = Objects.requireNonNull(packageName);
+            mUser = Objects.requireNonNull(user);
             return this;
         }
 
@@ -266,7 +266,7 @@
         @Deprecated
         public Builder setTarget(@NonNull ShortcutInfo info) {
             setTarget(info.getPackage(), info.getUserHandle());
-            mShortcutInfo = Preconditions.checkNotNull(info);
+            mShortcutInfo = Objects.requireNonNull(info);
             return this;
         }
 
@@ -275,7 +275,7 @@
          */
         @NonNull
         public Builder setClassName(@NonNull String className) {
-            mClassName = Preconditions.checkNotNull(className);
+            mClassName = Objects.requireNonNull(className);
             return this;
         }
 
diff --git a/core/java/android/app/slice/Slice.java b/core/java/android/app/slice/Slice.java
index a7319f6..823fdd2 100644
--- a/core/java/android/app/slice/Slice.java
+++ b/core/java/android/app/slice/Slice.java
@@ -28,7 +28,6 @@
 import android.os.Parcelable;
 
 import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -428,7 +427,7 @@
          * @see SliceItem#getSubType()
          */
         public Builder addSubSlice(@NonNull Slice slice, @Nullable @SliceSubtype String subType) {
-            Preconditions.checkNotNull(slice);
+            Objects.requireNonNull(slice);
             mItems.add(new SliceItem(slice, SliceItem.FORMAT_SLICE, subType,
                     slice.getHints().toArray(new String[slice.getHints().size()])));
             return this;
@@ -441,8 +440,8 @@
          */
         public Slice.Builder addAction(@NonNull PendingIntent action, @NonNull Slice s,
                 @Nullable @SliceSubtype String subType) {
-            Preconditions.checkNotNull(action);
-            Preconditions.checkNotNull(s);
+            Objects.requireNonNull(action);
+            Objects.requireNonNull(s);
             List<String> hints = s.getHints();
             s.mSpec = null;
             mItems.add(new SliceItem(action, s, SliceItem.FORMAT_ACTION, subType, hints.toArray(
@@ -468,7 +467,7 @@
          */
         public Builder addIcon(Icon icon, @Nullable @SliceSubtype String subType,
                 @SliceHint List<String> hints) {
-            Preconditions.checkNotNull(icon);
+            Objects.requireNonNull(icon);
             mItems.add(new SliceItem(icon, SliceItem.FORMAT_IMAGE, subType, hints));
             return this;
         }
@@ -481,7 +480,7 @@
         public Slice.Builder addRemoteInput(RemoteInput remoteInput,
                 @Nullable @SliceSubtype String subType,
                 @SliceHint List<String> hints) {
-            Preconditions.checkNotNull(remoteInput);
+            Objects.requireNonNull(remoteInput);
             mItems.add(new SliceItem(remoteInput, SliceItem.FORMAT_REMOTE_INPUT,
                     subType, hints));
             return this;
@@ -529,7 +528,7 @@
          */
         public Slice.Builder addBundle(Bundle bundle, @Nullable @SliceSubtype String subType,
                 @SliceHint List<String> hints) {
-            Preconditions.checkNotNull(bundle);
+            Objects.requireNonNull(bundle);
             mItems.add(new SliceItem(bundle, SliceItem.FORMAT_BUNDLE, subType,
                     hints));
             return this;
diff --git a/core/java/android/app/slice/SliceManager.java b/core/java/android/app/slice/SliceManager.java
index 90ecce2..4da1acb 100644
--- a/core/java/android/app/slice/SliceManager.java
+++ b/core/java/android/app/slice/SliceManager.java
@@ -51,6 +51,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -241,7 +242,7 @@
      * @see Slice
      */
     public @Nullable Slice bindSlice(@NonNull Uri uri, @NonNull Set<SliceSpec> supportedSpecs) {
-        Preconditions.checkNotNull(uri, "uri");
+        Objects.requireNonNull(uri, "uri");
         ContentResolver resolver = mContext.getContentResolver();
         try (ContentProviderClient provider = resolver.acquireUnstableContentProviderClient(uri)) {
             if (provider == null) {
@@ -336,7 +337,7 @@
     }
 
     private Uri resolveStatic(@NonNull Intent intent, ContentResolver resolver) {
-        Preconditions.checkNotNull(intent, "intent");
+        Objects.requireNonNull(intent, "intent");
         Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null
                 || intent.getData() != null,
                 "Slice intent must be explicit %s", intent);
@@ -371,7 +372,7 @@
      */
     public @Nullable Slice bindSlice(@NonNull Intent intent,
             @NonNull Set<SliceSpec> supportedSpecs) {
-        Preconditions.checkNotNull(intent, "intent");
+        Objects.requireNonNull(intent, "intent");
         Preconditions.checkArgument(intent.getComponent() != null || intent.getPackage() != null
                 || intent.getData() != null,
                 "Slice intent must be explicit %s", intent);
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 7412970..4346d97 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -16,8 +16,6 @@
 
 package android.app.usage;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 import android.annotation.Nullable;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
@@ -42,6 +40,8 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.util.Objects;
+
 /**
  * Provides access to network usage history and statistics. Usage data is collected in
  * discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details.
@@ -418,7 +418,7 @@
     /** @hide */
     public void registerUsageCallback(NetworkTemplate template, int networkType,
             long thresholdBytes, UsageCallback callback, @Nullable Handler handler) {
-        checkNotNull(callback, "UsageCallback cannot be null");
+        Objects.requireNonNull(callback, "UsageCallback cannot be null");
 
         final Looper looper;
         if (handler == null) {
diff --git a/core/java/android/app/usage/StorageStatsManager.java b/core/java/android/app/usage/StorageStatsManager.java
index eecf092..1ef1563 100644
--- a/core/java/android/app/usage/StorageStatsManager.java
+++ b/core/java/android/app/usage/StorageStatsManager.java
@@ -63,8 +63,8 @@
 
     /** {@hide} */
     public StorageStatsManager(Context context, IStorageStatsManager service) {
-        mContext = Preconditions.checkNotNull(context);
-        mService = Preconditions.checkNotNull(service);
+        mContext = Objects.requireNonNull(context);
+        mService = Objects.requireNonNull(service);
     }
 
     /** {@hide} */
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 47edf2e..32803ab 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -202,6 +202,7 @@
     public static final String TAG_OVERLAY = "overlay";
     public static final String TAG_PACKAGE = "package";
     public static final String TAG_PACKAGE_VERIFIER = "package-verifier";
+    public static final String TAG_FEATURE = "feature";
     public static final String TAG_PERMISSION = "permission";
     public static final String TAG_PERMISSION_GROUP = "permission-group";
     public static final String TAG_PERMISSION_TREE = "permission-tree";
diff --git a/core/java/android/content/pm/parsing/AndroidPackage.java b/core/java/android/content/pm/parsing/AndroidPackage.java
index 0562dff..990c835 100644
--- a/core/java/android/content/pm/parsing/AndroidPackage.java
+++ b/core/java/android/content/pm/parsing/AndroidPackage.java
@@ -27,6 +27,7 @@
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
 import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedFeature;
 import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
 import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
 import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
@@ -245,6 +246,9 @@
     List<ParsedInstrumentation> getInstrumentations();
 
     @Nullable
+    List<ParsedFeature> getFeatures();
+
+    @Nullable
     List<ParsedPermissionGroup> getPermissionGroups();
 
     @Nullable
diff --git a/core/java/android/content/pm/parsing/ApkParseUtils.java b/core/java/android/content/pm/parsing/ApkParseUtils.java
index 3f22967..a001ada 100644
--- a/core/java/android/content/pm/parsing/ApkParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkParseUtils.java
@@ -793,6 +793,10 @@
                     parseResult = parseKeySets(parseInput, parsingPackage, res, parser);
                     success = parseResult.isSuccess();
                     break;
+                case PackageParser.TAG_FEATURE:
+                    parseResult = parseFeature(parseInput, parsingPackage, res, parser);
+                    success = parseResult.isSuccess();
+                    break;
                 case PackageParser.TAG_PERMISSION_GROUP:
                     parseResult = parsePermissionGroup(parseInput, parsingPackage, res,
                             parser);
@@ -880,6 +884,13 @@
             );
         }
 
+        if (!ComponentParseUtils.ParsedFeature.isCombinationValid(parsingPackage.getFeatures())) {
+            return parseInput.error(
+                    INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                    "Combination <feature> tags are not valid"
+            );
+        }
+
         convertNewPermissions(parsingPackage);
 
         convertSplitPermissions(parsingPackage);
@@ -1260,6 +1271,31 @@
         return parseInput.success(parsingPackage);
     }
 
+    private static ParseResult parseFeature(
+            ParseInput parseInput,
+            ParsingPackage parsingPackage,
+            Resources res,
+            XmlResourceParser parser
+    ) throws IOException, XmlPullParserException {
+        // TODO(b/135203078): Remove, replace with ParseResult
+        String[] outError = new String[1];
+
+        ComponentParseUtils.ParsedFeature parsedFeature =
+                ComponentParseUtils.parseFeature(res, parser, outError);
+
+        if (parsedFeature == null || outError[0] != null) {
+            return parseInput.error(
+                    PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+                    outError[0]
+            );
+        }
+
+        parsingPackage.addFeature(parsedFeature);
+
+        return parseInput.success(parsingPackage);
+    }
+
+
     private static ParseResult parsePermissionGroup(
             ParseInput parseInput,
             ParsingPackage parsingPackage,
diff --git a/core/java/android/content/pm/parsing/ComponentParseUtils.java b/core/java/android/content/pm/parsing/ComponentParseUtils.java
index fc210b2..7b24d3d 100644
--- a/core/java/android/content/pm/parsing/ComponentParseUtils.java
+++ b/core/java/android/content/pm/parsing/ComponentParseUtils.java
@@ -24,6 +24,9 @@
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
 
 import android.annotation.CallSuper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringRes;
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityTaskManager;
 import android.content.ComponentName;
@@ -47,6 +50,7 @@
 import android.os.Parcelable;
 import android.os.PatternMatcher;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Slog;
@@ -54,6 +58,7 @@
 import android.view.Gravity;
 
 import com.android.internal.R;
+import com.android.internal.util.DataClass;
 import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -62,6 +67,7 @@
 import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
@@ -931,6 +937,186 @@
         };
     }
 
+    /**
+     * A {@link android.R.styleable#AndroidManifestFeature &lt;feature&gt;} tag parsed from the
+     * manifest.
+     */
+    // @DataClass verifier is broken, hence comment out for now
+    public static class ParsedFeature implements Parcelable {
+        /** Maximum length of featureId */
+        public static final int MAX_FEATURE_ID_LEN = 50;
+
+        /** Maximum amount of features per package */
+        private static final int MAX_NUM_FEATURES = 1000;
+
+        /** Id of the feature */
+        public final @NonNull String id;
+
+        /** User visible label fo the feature */
+        public final @StringRes int label;
+
+        /** Ids of previously declared features this feature inherits from */
+        public final @NonNull List<String> inheritFrom;
+
+        /**
+         * @return Is this set of features a valid combination for a single package?
+         */
+        public static boolean isCombinationValid(@Nullable List<ParsedFeature> features) {
+            if (features == null) {
+                return true;
+            }
+
+            ArraySet<String> featureIds = new ArraySet<>(features.size());
+            ArraySet<String> inheritFromFeatureIds = new ArraySet<>();
+
+            int numFeatures = features.size();
+            if (numFeatures > MAX_NUM_FEATURES) {
+                return false;
+            }
+
+            for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
+                boolean wasAdded = featureIds.add(features.get(featureNum).id);
+                if (!wasAdded) {
+                    // feature id is not unique
+                    return false;
+                }
+            }
+
+            for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
+                ParsedFeature feature = features.get(featureNum);
+
+                int numInheritFrom = feature.inheritFrom.size();
+                for (int inheritFromNum = 0; inheritFromNum < numInheritFrom; inheritFromNum++) {
+                    String inheritFrom = feature.inheritFrom.get(inheritFromNum);
+
+                    if (featureIds.contains(inheritFrom)) {
+                        // Cannot inherit from a feature that is still defined
+                        return false;
+                    }
+
+                    boolean wasAdded = inheritFromFeatureIds.add(inheritFrom);
+                    if (!wasAdded) {
+                        // inheritFrom is not unique
+                        return false;
+                    }
+                }
+            }
+
+            return true;
+        }
+
+
+
+        // Code below generated by codegen v1.0.14.
+        //
+        // DO NOT MODIFY!
+        // CHECKSTYLE:OFF Generated code
+        //
+        // To regenerate run:
+        // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/ComponentParseUtils.java
+        //
+        // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+        //   Settings > Editor > Code Style > Formatter Control
+        //@formatter:off
+
+
+        /**
+         * Creates a new ParsedFeature.
+         *
+         * @param id
+         *   Id of the feature
+         * @param label
+         *   User visible label fo the feature (if defined as resource)
+         * @param inheritFrom
+         *   Ids of previously declared features this feature inherits from
+         */
+        @DataClass.Generated.Member
+        public ParsedFeature(
+                @NonNull String id,
+                @StringRes int label,
+                @NonNull List<String> inheritFrom) {
+            this.id = id;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, id);
+            this.label = label;
+            com.android.internal.util.AnnotationValidations.validate(
+                    StringRes.class, null, label);
+            this.inheritFrom = inheritFrom;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, inheritFrom);
+
+            // onConstructed(); // You can define this method to get a callback
+        }
+
+        @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(id);
+            dest.writeInt(label);
+            dest.writeStringList(inheritFrom);
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public int describeContents() { return 0; }
+
+        /** @hide */
+        @SuppressWarnings({"unchecked", "RedundantCast"})
+        @DataClass.Generated.Member
+        protected ParsedFeature(@NonNull Parcel in) {
+            // You can override field unparcelling by defining methods like:
+            // static FieldType unparcelFieldName(Parcel in) { ... }
+
+            String _id = in.readString();
+            int _label = in.readInt();
+            List<String> _inheritFrom = new ArrayList<>();
+            in.readStringList(_inheritFrom);
+
+            this.id = _id;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, id);
+            this.label = _label;
+            com.android.internal.util.AnnotationValidations.validate(
+                    StringRes.class, null, label);
+            this.inheritFrom = _inheritFrom;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, inheritFrom);
+
+            // onConstructed(); // You can define this method to get a callback
+        }
+
+        @DataClass.Generated.Member
+        public static final @NonNull Parcelable.Creator<ParsedFeature> CREATOR
+                = new Parcelable.Creator<ParsedFeature>() {
+            @Override
+            public ParsedFeature[] newArray(int size) {
+                return new ParsedFeature[size];
+            }
+
+            @Override
+            public ParsedFeature createFromParcel(@NonNull Parcel in) {
+                return new ParsedFeature(in);
+            }
+        };
+
+        /*@DataClass.Generated(
+                time = 1576783172965L,
+                codegenVersion = "1.0.14",
+                sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ComponentParseUtils.java",
+                inputSignatures = "public final @android.annotation.NonNull java.lang.String id\npublic final @android.annotation.StringRes int label\npublic final @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\npublic static  boolean isCombinationValid(java.util.List<android.content.pm.parsing.ParsedFeature>)\nclass ParsedFeature extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass")
+         */
+        @Deprecated
+        private void __metadata() {}
+
+
+        //@formatter:on
+        // End of generated code
+
+    }
+
     public static class ParsedPermission extends ParsedComponent<ParsedIntentInfo> {
 
         public String backgroundPermission;
@@ -2566,6 +2752,85 @@
         return result;
     }
 
+    public static ParsedFeature parseFeature(
+            Resources res,
+            XmlResourceParser parser,
+            String[] outError
+    ) throws IOException, XmlPullParserException {
+        String featureId;
+        int label;
+        List<String> inheritFrom = null;
+
+        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestFeature);
+        if (sa == null) {
+            outError[0] = "<feature> could not be parsed";
+            return null;
+        }
+
+        try {
+            featureId = sa.getNonConfigurationString(R.styleable.AndroidManifestFeature_featureId,
+                    0);
+            if (featureId == null) {
+                outError[0] = "<featureId> does not specify android:featureId";
+                return null;
+            }
+            if (featureId.length() > ParsedFeature.MAX_FEATURE_ID_LEN) {
+                outError[0] = "<featureId> is too long. Max length is "
+                        + ParsedFeature.MAX_FEATURE_ID_LEN;
+                return null;
+            }
+
+            label = sa.getResourceId(R.styleable.AndroidManifestFeature_label, 0);
+            if (label == Resources.ID_NULL) {
+                outError[0] = "<featureId> does not specify android:label";
+                return null;
+            }
+        } finally {
+            sa.recycle();
+        }
+
+        int type;
+        final int innerDepth = parser.getDepth();
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            if (tagName.equals("inherit-from")) {
+                sa = res.obtainAttributes(parser, R.styleable.AndroidManifestFeatureInheritFrom);
+                if (sa == null) {
+                    outError[0] = "<inherit-from> could not be parsed";
+                    return null;
+                }
+
+                try {
+                    String inheritFromId = sa.getNonConfigurationString(
+                            R.styleable.AndroidManifestFeatureInheritFrom_featureId,0);
+
+                    if (inheritFrom == null) {
+                        inheritFrom = new ArrayList<>();
+                    }
+                    inheritFrom.add(inheritFromId);
+                } finally {
+                    sa.recycle();
+                }
+            } else {
+                outError[0] = "Bad element under <feature>: " + tagName;
+                return null;
+            }
+        }
+
+        if (inheritFrom == null) {
+            inheritFrom = Collections.emptyList();
+        } else {
+            ((ArrayList) inheritFrom).trimToSize();
+        }
+
+        return new ParsedFeature(featureId, label, inheritFrom);
+    }
+
     public static ParsedPermission parsePermission(
             ParsingPackage parsingPackage,
             Resources res,
diff --git a/core/java/android/content/pm/parsing/PackageImpl.java b/core/java/android/content/pm/parsing/PackageImpl.java
index 18dee23..8677fce 100644
--- a/core/java/android/content/pm/parsing/PackageImpl.java
+++ b/core/java/android/content/pm/parsing/PackageImpl.java
@@ -36,6 +36,7 @@
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
 import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedFeature;
 import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
 import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo;
 import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
@@ -175,6 +176,9 @@
     private ArrayList<ComponentParseUtils.ParsedProvider> providers;
 
     @Nullable
+    private ArrayList<ComponentParseUtils.ParsedFeature> features;
+
+    @Nullable
     private ArrayList<ComponentParseUtils.ParsedPermission> permissions;
 
     @Nullable
@@ -580,6 +584,12 @@
         return permissions;
     }
 
+    @Nullable
+    @Override
+    public List<ParsedFeature> getFeatures() {
+        return features;
+    }
+
     @Override
     public String getCpuAbiOverride() {
         return cpuAbiOverride;
@@ -792,6 +802,12 @@
     }
 
     @Override
+    public PackageImpl addFeature(ParsedFeature feature) {
+        this.features = ArrayUtils.add(this.features, feature);
+        return this;
+    }
+
+    @Override
     public PackageImpl addPermission(ParsedPermission permission) {
         this.permissions = ArrayUtils.add(this.permissions, permission);
         return this;
@@ -3021,6 +3037,7 @@
         dest.writeTypedList(this.receivers);
         dest.writeTypedList(this.services);
         dest.writeTypedList(this.providers);
+        dest.writeTypedList(this.features);
         dest.writeTypedList(this.permissions);
         dest.writeTypedList(this.permissionGroups);
         dest.writeTypedList(this.instrumentations);
@@ -3173,6 +3190,7 @@
         this.receivers = in.createTypedArrayList(ParsedActivity.CREATOR);
         this.services = in.createTypedArrayList(ParsedService.CREATOR);
         this.providers = in.createTypedArrayList(ParsedProvider.CREATOR);
+        this.features = in.createTypedArrayList(ParsedFeature.CREATOR);
         this.permissions = in.createTypedArrayList(ParsedPermission.CREATOR);
         this.permissionGroups = in.createTypedArrayList(ParsedPermissionGroup.CREATOR);
         this.instrumentations = in.createTypedArrayList(ParsedInstrumentation.CREATOR);
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 47dac55..411c749 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -24,6 +24,7 @@
 import android.content.pm.PackageParser;
 import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
 import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
+import android.content.pm.parsing.ComponentParseUtils.ParsedFeature;
 import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
 import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
 import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
@@ -64,6 +65,8 @@
 
     ParsingPackage addOverlayable(String overlayableName, String actorName);
 
+    ParsingPackage addFeature(ParsedFeature permission);
+
     ParsingPackage addPermission(ParsedPermission permission);
 
     ParsingPackage addPermissionGroup(ParsedPermissionGroup permissionGroup);
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index cc5d3b1..0a8547a 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -24,13 +24,12 @@
 import android.os.Bundle;
 import android.util.Log;
 
-import com.android.internal.util.Preconditions;
-
 import java.lang.ref.WeakReference;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 
 /**
@@ -416,8 +415,8 @@
 
     @Override
     public void setNotificationUris(@NonNull ContentResolver cr, @NonNull List<Uri> notifyUris) {
-        Preconditions.checkNotNull(cr);
-        Preconditions.checkNotNull(notifyUris);
+        Objects.requireNonNull(cr);
+        Objects.requireNonNull(notifyUris);
 
         setNotificationUris(cr, notifyUris, cr.getUserId(), true);
     }
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index caf3e93..cad4e81 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -60,6 +60,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Objects;
 import java.util.WeakHashMap;
 
 /**
@@ -2691,7 +2692,7 @@
              */
             @NonNull
             public Builder setJournalMode(@NonNull  String journalMode) {
-                Preconditions.checkNotNull(journalMode);
+                Objects.requireNonNull(journalMode);
                 mJournalMode = journalMode;
                 return this;
             }
@@ -2703,7 +2704,7 @@
              */
             @NonNull
             public Builder setSynchronousMode(@NonNull String syncMode) {
-                Preconditions.checkNotNull(syncMode);
+                Objects.requireNonNull(syncMode);
                 mSyncMode = syncMode;
                 return this;
             }
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index 62cec0e..0608cb3 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -27,9 +27,8 @@
 import android.os.FileUtils;
 import android.util.Log;
 
-import com.android.internal.util.Preconditions;
-
 import java.io.File;
+import java.util.Objects;
 
 /**
  * A helper class to manage database creation and version management.
@@ -161,7 +160,7 @@
     private SQLiteOpenHelper(@Nullable Context context, @Nullable String name, int version,
             int minimumSupportedVersion,
             @NonNull SQLiteDatabase.OpenParams.Builder openParamsBuilder) {
-        Preconditions.checkNotNull(openParamsBuilder);
+        Objects.requireNonNull(openParamsBuilder);
         if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);
 
         mContext = context;
@@ -245,7 +244,7 @@
      * @throws IllegalStateException if the database is already open
      */
     public void setOpenParams(@NonNull SQLiteDatabase.OpenParams openParams) {
-        Preconditions.checkNotNull(openParams);
+        Objects.requireNonNull(openParams);
         synchronized (this) {
             if (mDatabase != null && mDatabase.isOpen()) {
                 throw new IllegalStateException(
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 41435c9..67e7a4c 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -50,8 +50,6 @@
 import android.util.SparseArray;
 import android.view.Surface;
 
-import com.android.internal.util.Preconditions;
-
 import java.util.AbstractMap.SimpleEntry;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -60,6 +58,7 @@
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -2482,7 +2481,7 @@
         private final Handler mHandler;
 
         public CameraHandlerExecutor(@NonNull Handler handler) {
-            mHandler = Preconditions.checkNotNull(handler);
+            mHandler = Objects.requireNonNull(handler);
         }
 
         @Override
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 6f90db4..248c145 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -73,14 +73,13 @@
 import android.util.Range;
 import android.util.Size;
 
-import com.android.internal.util.Preconditions;
-
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Implementation of camera metadata marshal/unmarshal across Binder to
@@ -432,7 +431,7 @@
      * @return the field corresponding to the {@code key}, or {@code null} if no value was set
      */
     public <T> T get(Key<T> key) {
-        Preconditions.checkNotNull(key, "key must not be null");
+        Objects.requireNonNull(key, "key must not be null");
 
         // Check if key has been overridden to use a wrapper class on the java side.
         GetCommand g = sGetCommandMap.get(key);
diff --git a/core/java/android/hardware/camera2/params/BlackLevelPattern.java b/core/java/android/hardware/camera2/params/BlackLevelPattern.java
index 283977f..c3dc25f 100644
--- a/core/java/android/hardware/camera2/params/BlackLevelPattern.java
+++ b/core/java/android/hardware/camera2/params/BlackLevelPattern.java
@@ -16,9 +16,8 @@
 
 package android.hardware.camera2.params;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * Immutable class to store a 4-element vector of integers corresponding to a 2x2 pattern
@@ -88,7 +87,7 @@
      * @throws NullPointerException if the destination is null.
      */
     public void copyTo(int[] destination, int offset) {
-        checkNotNull(destination, "destination must not be null");
+        Objects.requireNonNull(destination, "destination must not be null");
         if (offset < 0) {
             throw new IllegalArgumentException("Null offset passed to copyTo");
         }
diff --git a/core/java/android/hardware/camera2/params/LensShadingMap.java b/core/java/android/hardware/camera2/params/LensShadingMap.java
index 9eb276f..38c1dd4 100644
--- a/core/java/android/hardware/camera2/params/LensShadingMap.java
+++ b/core/java/android/hardware/camera2/params/LensShadingMap.java
@@ -25,12 +25,12 @@
 import static com.android.internal.util.Preconditions.checkArgumentNonnegative;
 import static com.android.internal.util.Preconditions.checkArgumentPositive;
 import static com.android.internal.util.Preconditions.checkArrayElementsInRange;
-import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.utils.HashCodeHelpers;
 
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * Immutable class for describing a {@code 4 x N x M} lens shading map of floats.
@@ -70,7 +70,7 @@
 
         mRows = checkArgumentPositive(rows, "rows must be positive");
         mColumns = checkArgumentPositive(columns, "columns must be positive");
-        mElements = checkNotNull(elements, "elements must not be null");
+        mElements = Objects.requireNonNull(elements, "elements must not be null");
 
         if (elements.length != getGainFactorCount()) {
             throw new IllegalArgumentException("elements must be " + getGainFactorCount() +
@@ -203,7 +203,7 @@
      */
     public void copyGainFactors(final float[] destination, final int offset) {
         checkArgumentNonnegative(offset, "offset must not be negative");
-        checkNotNull(destination, "destination must not be null");
+        Objects.requireNonNull(destination, "destination must not be null");
         if (destination.length + offset < getGainFactorCount()) {
             throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
         }
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index 336edc1..478922d 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -17,7 +17,6 @@
 package android.hardware.camera2.params;
 
 import static com.android.internal.util.Preconditions.checkArrayElementsNotNull;
-import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.graphics.ImageFormat;
 import android.graphics.PixelFormat;
@@ -491,7 +490,7 @@
      * @see #isOutputSupportedFor(Surface)
      */
     public static <T> boolean isOutputSupportedFor(Class<T> klass) {
-        checkNotNull(klass, "klass must not be null");
+        Objects.requireNonNull(klass, "klass must not be null");
 
         if (klass == android.media.ImageReader.class) {
             return true;
@@ -548,7 +547,7 @@
      * @see #isOutputSupportedFor(Class)
      */
     public boolean isOutputSupportedFor(Surface surface) {
-        checkNotNull(surface, "surface must not be null");
+        Objects.requireNonNull(surface, "surface must not be null");
 
         Size surfaceSize = SurfaceUtils.getSurfaceSize(surface);
         int surfaceFormat = SurfaceUtils.getSurfaceFormat(surface);
@@ -897,7 +896,7 @@
      * @see PixelFormat
      */
     public long getOutputMinFrameDuration(int format, Size size) {
-        checkNotNull(size, "size must not be null");
+        Objects.requireNonNull(size, "size must not be null");
         checkArgumentFormatSupported(format, /*output*/true);
 
         return getInternalFormatDuration(imageFormatToInternal(format),
diff --git a/core/java/android/hardware/display/AmbientBrightnessDayStats.java b/core/java/android/hardware/display/AmbientBrightnessDayStats.java
index 350bc30..26fd265 100644
--- a/core/java/android/hardware/display/AmbientBrightnessDayStats.java
+++ b/core/java/android/hardware/display/AmbientBrightnessDayStats.java
@@ -27,6 +27,7 @@
 
 import java.time.LocalDate;
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * AmbientBrightnessDayStats stores and manipulates brightness stats over a single day.
@@ -70,8 +71,8 @@
      */
     public AmbientBrightnessDayStats(@NonNull LocalDate localDate,
             @NonNull float[] bucketBoundaries, float[] stats) {
-        Preconditions.checkNotNull(localDate);
-        Preconditions.checkNotNull(bucketBoundaries);
+        Objects.requireNonNull(localDate);
+        Objects.requireNonNull(bucketBoundaries);
         Preconditions.checkArrayElementsInRange(bucketBoundaries, 0, Float.MAX_VALUE,
                 "bucketBoundaries");
         if (bucketBoundaries.length < 1) {
diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java
index 0a38538..13122d2 100644
--- a/core/java/android/hardware/display/BrightnessConfiguration.java
+++ b/core/java/android/hardware/display/BrightnessConfiguration.java
@@ -541,8 +541,8 @@
          * @throws IllegalArgumentException if the nit levels are not monotonically increasing.
          */
         public Builder(float[] lux, float[] nits) {
-            Preconditions.checkNotNull(lux);
-            Preconditions.checkNotNull(nits);
+            Objects.requireNonNull(lux);
+            Objects.requireNonNull(nits);
             if (lux.length == 0 || nits.length == 0) {
                 throw new IllegalArgumentException("Lux and nits arrays must not be empty");
             }
diff --git a/core/java/android/hardware/usb/UsbAccessory.java b/core/java/android/hardware/usb/UsbAccessory.java
index a725205..a94266b 100644
--- a/core/java/android/hardware/usb/UsbAccessory.java
+++ b/core/java/android/hardware/usb/UsbAccessory.java
@@ -26,6 +26,8 @@
 import com.android.internal.util.Preconditions;
 import java.util.Objects;
 
+import java.util.Objects;
+
 /**
  * A class representing a USB accessory, which is an external hardware component
  * that communicates with an android application over USB.
diff --git a/core/java/android/hardware/usb/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java
index 67e05c8..9636b13 100644
--- a/core/java/android/hardware/usb/UsbDevice.java
+++ b/core/java/android/hardware/usb/UsbDevice.java
@@ -27,6 +27,8 @@
 import com.android.internal.util.Preconditions;
 import java.util.Objects;
 
+import java.util.Objects;
+
 /**
  * This class represents a USB device attached to the android device with the android device
  * acting as the USB host.
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index a45f703..ffb97c0 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -517,7 +517,9 @@
         @Override
         public void onCreateInlineSuggestionsRequest(ComponentName componentName,
                 AutofillId autofillId, IInlineSuggestionsRequestCallback cb) {
-            Log.d(TAG, "InputMethodService received onCreateInlineSuggestionsRequest()");
+            if (DEBUG) {
+                Log.d(TAG, "InputMethodService received onCreateInlineSuggestionsRequest()");
+            }
             handleOnCreateInlineSuggestionsRequest(componentName, autofillId, cb);
         }
 
@@ -722,15 +724,6 @@
     }
 
     /**
-     * Returns whether inline suggestions are enabled on this service.
-     *
-     * TODO(b/137800469): check XML for value.
-     */
-    private boolean isInlineSuggestionsEnabled() {
-        return true;
-    }
-
-    /**
      * Sends an {@link InlineSuggestionsRequest} obtained from
      * {@link #onCreateInlineSuggestionsRequest()} to the current Autofill Session through
      * {@link IInlineSuggestionsRequestCallback#onInlineSuggestionsRequest}.
@@ -763,22 +756,18 @@
 
     private void handleOnCreateInlineSuggestionsRequest(@NonNull ComponentName componentName,
             @NonNull AutofillId autofillId, @NonNull IInlineSuggestionsRequestCallback callback) {
-        mInlineSuggestionsRequestInfo = new InlineSuggestionsRequestInfo(componentName, autofillId,
-                callback);
-
-        if (!isInlineSuggestionsEnabled()) {
+        if (!mInputStarted) {
             try {
+                Log.w(TAG, "onStartInput() not called yet");
                 callback.onInlineSuggestionsUnsupported();
             } catch (RemoteException e) {
-                Log.w(TAG, "handleMakeInlineSuggestionsRequest() RemoteException:" + e);
+                Log.w(TAG, "Failed to call onInlineSuggestionsUnsupported.", e);
             }
             return;
         }
 
-        if (!mInputStarted) {
-            Log.w(TAG, "onStartInput() not called yet");
-            return;
-        }
+        mInlineSuggestionsRequestInfo = new InlineSuggestionsRequestInfo(componentName, autofillId,
+                callback);
 
         makeInlineSuggestionsRequest();
     }
@@ -786,8 +775,12 @@
     private void handleOnInlineSuggestionsResponse(@NonNull ComponentName componentName,
             @NonNull AutofillId autofillId, @NonNull InlineSuggestionsResponse response) {
         if (!mInlineSuggestionsRequestInfo.validate(componentName)) {
-            Log.d(TAG, "Response component=" + componentName + " differs from request component="
-                    + mInlineSuggestionsRequestInfo.mComponentName + ", ignoring response");
+            if (DEBUG) {
+                Log.d(TAG,
+                        "Response component=" + componentName + " differs from request component="
+                                + mInlineSuggestionsRequestInfo.mComponentName
+                                + ", ignoring response");
+            }
             return;
         }
         onInlineSuggestionsResponse(response);
@@ -859,7 +852,7 @@
          */
         public boolean validate(ComponentName componentName) {
             final boolean result = componentName.equals(mComponentName);
-            if (!result) {
+            if (DEBUG && !result) {
                 Log.d(TAG, "Cached request info ComponentName=" + mComponentName
                         + " differs from received ComponentName=" + componentName);
             }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 3ed51d7..fbd90bd 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -3072,6 +3072,7 @@
      * @hide
      */
     @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_AIRPLANE_MODE,
             android.Manifest.permission.NETWORK_SETTINGS,
             android.Manifest.permission.NETWORK_SETUP_WIZARD,
             android.Manifest.permission.NETWORK_STACK})
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
index 2138d553..63335a0 100644
--- a/core/java/android/os/incremental/IncrementalFileStorages.java
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -38,6 +38,7 @@
 import android.content.pm.DataLoaderParams;
 import android.content.pm.InstallationFile;
 import android.os.IVold;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.ArraySet;
@@ -208,7 +209,8 @@
         if (!hasObb()) {
             return;
         }
-        final String mainObbDir = String.format("/storage/emulated/0/Android/obb/%s", mPackageName);
+        final String obbDir = "/storage/emulated/0/Android/obb";
+        final String packageObbDir = String.format("%s/%s", obbDir, mPackageName);
         final String packageObbDirRoot =
                 String.format("/mnt/runtime/%s/emulated/0/Android/obb/", mPackageName);
         final String[] obbDirs = {
@@ -217,12 +219,12 @@
                 packageObbDirRoot + "full",
                 packageObbDirRoot + "default",
                 String.format("/data/media/0/Android/obb/%s", mPackageName),
-                mainObbDir,
+                packageObbDir,
         };
         try {
-            Slog.i(TAG, "Creating obb directory '" + mainObbDir + "'");
+            Slog.i(TAG, "Creating obb directory '" + packageObbDir + "'");
             final IVold vold = IVold.Stub.asInterface(ServiceManager.getServiceOrThrow("vold"));
-            vold.mkdirs(mainObbDir);
+            vold.setupAppDir(packageObbDir, obbDir, Process.ROOT_UID);
             for (String d : obbDirs) {
                 mObbStorage.bindPermanent(d);
             }
@@ -230,7 +232,7 @@
             Slog.e(TAG, "vold service is not found.");
             cleanUp();
         } catch (IOException | RemoteException ex) {
-            Slog.e(TAG, "Failed to create obb dir at: " + mainObbDir, ex);
+            Slog.e(TAG, "Failed to create obb dir at: " + packageObbDir, ex);
             cleanUp();
         }
     }
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index a3215a4..2583292 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -318,8 +318,7 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(allOf = {Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
-            Manifest.permission.PACKAGE_USAGE_STATS})
+    @RequiresPermission(Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS)
     public void startOneTimePermissionSession(@NonNull String packageName, long timeoutMillis,
             @ActivityManager.RunningAppProcessInfo.Importance int importanceToResetTimer,
             @ActivityManager.RunningAppProcessInfo.Importance int importanceToKeepSessionAlive) {
@@ -340,8 +339,7 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(allOf = {Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
-            Manifest.permission.PACKAGE_USAGE_STATS})
+    @RequiresPermission(Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS)
     public void stopOneTimePermissionSession(@NonNull String packageName) {
         try {
             mPermissionManager.stopOneTimePermissionSession(packageName,
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index fed3d7ba..c95e132 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -3559,7 +3559,8 @@
          * can manage DPC-owned APNs.
          * @hide
          */
-        public static final Uri DPC_URI = Uri.parse("content://telephony/carriers/dpc");
+        @SystemApi
+        public static final @NonNull Uri DPC_URI = Uri.parse("content://telephony/carriers/dpc");
 
         /**
          * The {@code content://} style URL to be called from Telephony to query APNs.
@@ -3868,6 +3869,13 @@
         public static final String USER_EDITABLE = "user_editable";
 
         /**
+         * Integer value denoting an invalid APN id
+         * @hide
+         */
+        @SystemApi
+        public static final int INVALID_APN_ID = -1;
+
+        /**
          * {@link #EDITED_STATUS APN edit status} indicates that this APN has not been edited or
          * fails to edit.
          * <p>Type: INTEGER </p>
diff --git a/core/java/android/service/autofill/AutofillServiceInfo.java b/core/java/android/service/autofill/AutofillServiceInfo.java
index b7ec281..fbc25a6 100644
--- a/core/java/android/service/autofill/AutofillServiceInfo.java
+++ b/core/java/android/service/autofill/AutofillServiceInfo.java
@@ -80,6 +80,8 @@
     @Nullable
     private final ArrayMap<String, Long> mCompatibilityPackages;
 
+    private final boolean mInlineSuggestionsEnabled;
+
     public AutofillServiceInfo(Context context, ComponentName comp, int userHandle)
             throws PackageManager.NameNotFoundException {
         this(context, getServiceInfoOrThrow(comp, userHandle));
@@ -112,11 +114,13 @@
         if (parser == null) {
             mSettingsActivity = null;
             mCompatibilityPackages = null;
+            mInlineSuggestionsEnabled = false;
             return;
         }
 
         String settingsActivity = null;
         ArrayMap<String, Long> compatibilityPackages = null;
+        boolean inlineSuggestionsEnabled = false; // false by default.
 
         try {
             final Resources resources = context.getPackageManager().getResourcesForApplication(
@@ -135,6 +139,8 @@
                             com.android.internal.R.styleable.AutofillService);
                     settingsActivity = afsAttributes.getString(
                             R.styleable.AutofillService_settingsActivity);
+                    inlineSuggestionsEnabled = afsAttributes.getBoolean(
+                            R.styleable.AutofillService_supportsInlineSuggestions, false);
                 } finally {
                     if (afsAttributes != null) {
                         afsAttributes.recycle();
@@ -150,6 +156,7 @@
 
         mSettingsActivity = settingsActivity;
         mCompatibilityPackages = compatibilityPackages;
+        mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
     }
 
     private ArrayMap<String, Long> parseCompatibilityPackages(XmlPullParser parser,
@@ -227,6 +234,10 @@
         return mCompatibilityPackages;
     }
 
+    public boolean isInlineSuggestionsEnabled() {
+        return mInlineSuggestionsEnabled;
+    }
+
     @Override
     public String toString() {
         final StringBuilder builder = new StringBuilder();
@@ -235,6 +246,7 @@
         builder.append(", settings:").append(mSettingsActivity);
         builder.append(", hasCompatPckgs:").append(mCompatibilityPackages != null
                 && !mCompatibilityPackages.isEmpty()).append("]");
+        builder.append(", inline suggestions enabled:").append(mInlineSuggestionsEnabled);
         return builder.toString();
     }
 
@@ -245,5 +257,7 @@
         pw.print(prefix); pw.print("Component: "); pw.println(getServiceInfo().getComponentName());
         pw.print(prefix); pw.print("Settings: "); pw.println(mSettingsActivity);
         pw.print(prefix); pw.print("Compat packages: "); pw.println(mCompatibilityPackages);
+        pw.print(prefix); pw.print("Inline Suggestions Enabled: ");
+        pw.println(mInlineSuggestionsEnabled);
     }
 }
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 484eddc..6334d9d 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -38,6 +38,7 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.service.autofill.Dataset;
 import android.service.autofill.augmented.PresentationParams.SystemPopupPresentationParams;
 import android.util.Log;
 import android.util.Pair;
@@ -47,6 +48,7 @@
 import android.view.autofill.AutofillValue;
 import android.view.autofill.IAugmentedAutofillManagerClient;
 import android.view.autofill.IAutofillWindowPresenter;
+import android.view.inputmethod.InlineSuggestionsRequest;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -106,10 +108,11 @@
         @Override
         public void onFillRequest(int sessionId, IBinder client, int taskId,
                 ComponentName componentName, AutofillId focusedId, AutofillValue focusedValue,
-                long requestTime, IFillCallback callback) {
+                long requestTime, @Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
+                IFillCallback callback) {
             mHandler.sendMessage(obtainMessage(AugmentedAutofillService::handleOnFillRequest,
                     AugmentedAutofillService.this, sessionId, client, taskId, componentName,
-                    focusedId, focusedValue, requestTime, callback));
+                    focusedId, focusedValue, requestTime, inlineSuggestionsRequest, callback));
         }
 
         @Override
@@ -212,6 +215,7 @@
     private void handleOnFillRequest(int sessionId, @NonNull IBinder client, int taskId,
             @NonNull ComponentName componentName, @NonNull AutofillId focusedId,
             @Nullable AutofillValue focusedValue, long requestTime,
+            @Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
             @NonNull IFillCallback callback) {
         if (mAutofillProxies == null) {
             mAutofillProxies = new SparseArray<>();
@@ -236,9 +240,8 @@
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
-        // TODO(b/146453195): pass the inline suggestion request over.
-        onFillRequest(new FillRequest(proxy, /* inlineSuggestionsRequest= */null),
-                cancellationSignal, new FillController(proxy), new FillCallback(proxy));
+        onFillRequest(new FillRequest(proxy, inlineSuggestionsRequest), cancellationSignal,
+                new FillController(proxy), new FillCallback(proxy));
     }
 
     private void handleOnDestroyAllFillWindowsRequest() {
@@ -484,6 +487,14 @@
             }
         }
 
+        public void onInlineSuggestionsDataReady(@NonNull List<Dataset> inlineSuggestionsData) {
+            try {
+                mCallback.onSuccess(inlineSuggestionsData.toArray(new Dataset[]{}));
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error calling back with the inline suggestions data: " + e);
+            }
+        }
+
         // Used (mostly) for metrics.
         public void report(@ReportEvent int event) {
             if (sVerbose) Log.v(TAG, "report(): " + event);
diff --git a/core/java/android/service/autofill/augmented/FillCallback.java b/core/java/android/service/autofill/augmented/FillCallback.java
index 0251386..b767799 100644
--- a/core/java/android/service/autofill/augmented/FillCallback.java
+++ b/core/java/android/service/autofill/augmented/FillCallback.java
@@ -21,9 +21,12 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.service.autofill.Dataset;
 import android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy;
 import android.util.Log;
 
+import java.util.List;
+
 /**
  * Callback used to indicate at {@link FillRequest} has been fulfilled.
  *
@@ -45,7 +48,7 @@
      * Sets the response associated with the request.
      *
      * @param response response associated with the request, or {@code null} if the service
-     * could not provide autofill for the request.
+     *                 could not provide autofill for the request.
      */
     public void onSuccess(@Nullable FillResponse response) {
         if (sDebug) Log.d(TAG, "onSuccess(): " + response);
@@ -55,6 +58,12 @@
             return;
         }
 
+        List<Dataset> inlineSuggestions = response.getInlineSuggestions();
+        if (inlineSuggestions != null && !inlineSuggestions.isEmpty()) {
+            mProxy.onInlineSuggestionsDataReady(inlineSuggestions);
+            return;
+        }
+
         final FillWindow fillWindow = response.getFillWindow();
         if (fillWindow != null) {
             fillWindow.show();
diff --git a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
index 103fc4d..4911348 100644
--- a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
+++ b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
@@ -22,6 +22,7 @@
 import android.service.autofill.augmented.IFillCallback;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
+import android.view.inputmethod.InlineSuggestionsRequest;
 
 import java.util.List;
 
@@ -35,7 +36,9 @@
     void onDisconnected();
     void onFillRequest(int sessionId, in IBinder autofillManagerClient, int taskId,
                        in ComponentName activityComponent, in AutofillId focusedId,
-                       in AutofillValue focusedValue, long requestTime, in IFillCallback callback);
+                       in AutofillValue focusedValue, long requestTime,
+                       in InlineSuggestionsRequest inlineSuggestionsRequest,
+                       in IFillCallback callback);
 
     void onDestroyAllFillWindowsRequest();
 }
diff --git a/core/java/android/service/controls/ControlsProviderService.java b/core/java/android/service/controls/ControlsProviderService.java
index 258ef23..eca8541 100644
--- a/core/java/android/service/controls/ControlsProviderService.java
+++ b/core/java/android/service/controls/ControlsProviderService.java
@@ -20,7 +20,6 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.Service;
 import android.content.Intent;
-import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -88,7 +87,7 @@
      * {@link Control.StatelessBuilder}).
      * @param controls
      */
-    public void onLoad(@NonNull List<Control> controls) {
+    public final void onLoad(@NonNull List<Control> controls) {
         Preconditions.checkNotNull(controls);
         List<Control> list = new ArrayList<>();
         for (Control control: controls) {
@@ -114,7 +113,7 @@
      * their state.
      * @param statefulControls
      */
-    public void onRefreshState(@NonNull List<Control> statefulControls) {
+    public final void onRefreshState(@NonNull List<Control> statefulControls) {
         Preconditions.checkNotNull(statefulControls);
         try {
             mCallback.onRefreshState(mToken, statefulControls);
@@ -128,7 +127,7 @@
      * @param controlId
      * @param response
      */
-    public void onControlActionResponse(
+    public final void onControlActionResponse(
             @NonNull String controlId, @ControlAction.ResponseResult int response) {
         Preconditions.checkNotNull(controlId);
         if (!ControlAction.isValidResponse(response)) {
diff --git a/core/java/android/telephony/SubscriptionPlan.java b/core/java/android/telephony/SubscriptionPlan.java
index 28a5c20..ff2f4ad 100644
--- a/core/java/android/telephony/SubscriptionPlan.java
+++ b/core/java/android/telephony/SubscriptionPlan.java
@@ -228,24 +228,6 @@
     }
 
     /**
-     * Return the networkTypes array converted to a {@link TelephonyManager.NetworkTypeBitMask}
-     * @hide
-     */
-    public long getNetworkTypesBitMask() {
-        // calculate bitmask the first time and save for future calls
-        if (networkTypesBitMask == 0) {
-            if (networkTypes == null) {
-                networkTypesBitMask = ~0;
-            } else {
-                for (int networkType : networkTypes) {
-                    networkTypesBitMask |= TelephonyManager.getBitMaskForNetworkType(networkType);
-                }
-            }
-        }
-        return networkTypesBitMask;
-    }
-
-    /**
      * Return an iterator that will return all valid data usage cycles based on
      * any recurrence rules. The iterator starts from the currently active cycle
      * and walks backwards through time.
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index 1e5a3b0..cf494ae 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -63,6 +63,8 @@
  * which is what clients use to communicate with the input method.
  */
 public interface InputMethod {
+    /** @hide **/
+    public static final String TAG = "InputMethod";
     /**
      * This is the interface name that a service implementing an input
      * method should say that it supports -- that is, this is the action it
@@ -111,6 +113,10 @@
     /**
      * Called to notify the IME that Autofill Frameworks requested an inline suggestions request.
      *
+     * @param componentName {@link ComponentName} of current app/activity.
+     * @param autofillId {@link AutofillId} of currently focused field.
+     * @param cb {@link IInlineSuggestionsRequestCallback} used to pass back the request object.
+     *
      * @hide
      */
     default void onCreateInlineSuggestionsRequest(ComponentName componentName,
@@ -118,7 +124,7 @@
         try {
             cb.onInlineSuggestionsUnsupported();
         } catch (RemoteException e) {
-            Log.w("InputMethod", "RemoteException calling onInlineSuggestionsUnsupported: " + e);
+            Log.w(TAG, "Failed to call onInlineSuggestionsUnsupported.", e);
         }
     }
 
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 34005ac..2864485 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -58,6 +58,7 @@
  * @attr ref android.R.styleable#InputMethod_settingsActivity
  * @attr ref android.R.styleable#InputMethod_isDefault
  * @attr ref android.R.styleable#InputMethod_supportsSwitchingToNextInputMethod
+ * @attr ref android.R.styleable#InputMethod_supportsInlineSuggestions
  */
 public final class InputMethodInfo implements Parcelable {
     static final String TAG = "InputMethodInfo";
@@ -111,6 +112,11 @@
     private final boolean mSupportsSwitchingToNextInputMethod;
 
     /**
+     * The flag whether this IME supports inline suggestions.
+     */
+    private final boolean mInlineSuggestionsEnabled;
+
+    /**
      * @param service the {@link ResolveInfo} corresponds in which the IME is implemented.
      * @return a unique ID to be returned by {@link #getId()}. We have used
      *         {@link ComponentName#flattenToShortString()} for this purpose (and it is already
@@ -152,6 +158,7 @@
         mId = computeId(service);
         boolean isAuxIme = true;
         boolean supportsSwitchingToNextInputMethod = false; // false as default
+        boolean inlineSuggestionsEnabled = false; // false as default
         mForceDefault = false;
 
         PackageManager pm = context.getPackageManager();
@@ -193,6 +200,8 @@
             supportsSwitchingToNextInputMethod = sa.getBoolean(
                     com.android.internal.R.styleable.InputMethod_supportsSwitchingToNextInputMethod,
                     false);
+            inlineSuggestionsEnabled = sa.getBoolean(
+                    com.android.internal.R.styleable.InputMethod_supportsInlineSuggestions, false);
             sa.recycle();
 
             final int depth = parser.getDepth();
@@ -263,6 +272,7 @@
         mIsDefaultResId = isDefaultResId;
         mIsAuxIme = isAuxIme;
         mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
+        mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
         mIsVrOnly = isVrOnly;
     }
 
@@ -272,6 +282,7 @@
         mIsDefaultResId = source.readInt();
         mIsAuxIme = source.readInt() == 1;
         mSupportsSwitchingToNextInputMethod = source.readInt() == 1;
+        mInlineSuggestionsEnabled = source.readInt() == 1;
         mIsVrOnly = source.readBoolean();
         mService = ResolveInfo.CREATOR.createFromParcel(source);
         mSubtypes = new InputMethodSubtypeArray(source);
@@ -286,7 +297,7 @@
         this(buildDummyResolveInfo(packageName, className, label), false /* isAuxIme */,
                 settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
                 false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
-                false /* isVrOnly */);
+                false /* inlineSuggestionsEnabled */, false /* isVrOnly */);
     }
 
     /**
@@ -297,7 +308,8 @@
             String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId,
             boolean forceDefault) {
         this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
-                true /* supportsSwitchingToNextInputMethod */, false /* isVrOnly */);
+                true /* supportsSwitchingToNextInputMethod */, false /* inlineSuggestionsEnabled */,
+                false /* isVrOnly */);
     }
 
     /**
@@ -307,6 +319,18 @@
     public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity,
             List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
             boolean supportsSwitchingToNextInputMethod, boolean isVrOnly) {
+        this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
+                supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly);
+    }
+
+    /**
+     * Temporary API for creating a built-in input method for test.
+     * @hide
+     */
+    public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity,
+            List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
+            boolean supportsSwitchingToNextInputMethod, boolean inlineSuggestionsEnabled,
+            boolean isVrOnly) {
         final ServiceInfo si = ri.serviceInfo;
         mService = ri;
         mId = new ComponentName(si.packageName, si.name).flattenToShortString();
@@ -316,6 +340,7 @@
         mSubtypes = new InputMethodSubtypeArray(subtypes);
         mForceDefault = forceDefault;
         mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
+        mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
         mIsVrOnly = isVrOnly;
     }
 
@@ -467,7 +492,8 @@
         pw.println(prefix + "mId=" + mId
                 + " mSettingsActivityName=" + mSettingsActivityName
                 + " mIsVrOnly=" + mIsVrOnly
-                + " mSupportsSwitchingToNextInputMethod=" + mSupportsSwitchingToNextInputMethod);
+                + " mSupportsSwitchingToNextInputMethod=" + mSupportsSwitchingToNextInputMethod
+                + " mInlineSuggestionsEnabled=" + mInlineSuggestionsEnabled);
         pw.println(prefix + "mIsDefaultResId=0x"
                 + Integer.toHexString(mIsDefaultResId));
         pw.println(prefix + "Service:");
@@ -528,6 +554,14 @@
     }
 
     /**
+     * @return true if this input method supports inline suggestions.
+     * @hide
+     */
+    public boolean isInlineSuggestionsEnabled() {
+        return mInlineSuggestionsEnabled;
+    }
+
+    /**
      * Used to package this object into a {@link Parcel}.
      *
      * @param dest The {@link Parcel} to be written.
@@ -540,6 +574,7 @@
         dest.writeInt(mIsDefaultResId);
         dest.writeInt(mIsAuxIme ? 1 : 0);
         dest.writeInt(mSupportsSwitchingToNextInputMethod ? 1 : 0);
+        dest.writeInt(mInlineSuggestionsEnabled ? 1 : 0);
         dest.writeBoolean(mIsVrOnly);
         mService.writeToParcel(dest, flags);
         mSubtypes.writeToParcel(dest);
diff --git a/core/java/android/view/textclassifier/TextClassificationSession.java b/core/java/android/view/textclassifier/TextClassificationSession.java
index abfbc6c..4329a20 100644
--- a/core/java/android/view/textclassifier/TextClassificationSession.java
+++ b/core/java/android/view/textclassifier/TextClassificationSession.java
@@ -20,6 +20,7 @@
 import android.view.textclassifier.SelectionEvent.InvocationMethod;
 
 import com.android.internal.util.Preconditions;
+
 import java.util.Objects;
 
 /**
@@ -183,6 +184,7 @@
                     mSmartEvent = event;
                     break;
                 case SelectionEvent.ACTION_ABANDON:
+                case SelectionEvent.ACTION_OVERTYPE:
                     if (mPrevEvent != null) {
                         event.setEntityType(mPrevEvent.getEntityType());
                     }
diff --git a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
index 7dbcbf9..28cb80d 100644
--- a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
+++ b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
@@ -22,6 +22,7 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.metrics.LogMaker;
+import android.os.Build;
 import android.util.Log;
 import android.view.textclassifier.TextClassification;
 import android.view.textclassifier.TextClassifier;
@@ -101,7 +102,8 @@
     private boolean mSmartSelectionTriggered;
     private String mModelName;
 
-    @UnsupportedAppUsage(trackingBug = 136637107)
+    @UnsupportedAppUsage(trackingBug = 136637107, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "See {@link android.view.textclassifier.TextClassifier}.")
     public SmartSelectionEventTracker(@NonNull Context context, @WidgetType int widgetType) {
         mWidgetType = widgetType;
         mWidgetVersion = null;
@@ -120,7 +122,8 @@
      *
      * @param event the selection event
      */
-    @UnsupportedAppUsage(trackingBug = 136637107)
+    @UnsupportedAppUsage(trackingBug = 136637107, maxTargetSdk = Build.VERSION_CODES.Q,
+            publicAlternatives = "See {@link android.view.textclassifier.TextClassifier}.")
     public void logEvent(@NonNull SelectionEvent event) {
         Objects.requireNonNull(event);
 
@@ -444,7 +447,8 @@
          *
          * @param start  the word index of the selected word
          */
-        @UnsupportedAppUsage(trackingBug = 136637107)
+        @UnsupportedAppUsage(trackingBug = 136637107, maxTargetSdk = Build.VERSION_CODES.Q,
+                publicAlternatives = "See {@link android.view.textclassifier.TextClassifier}.")
         public static SelectionEvent selectionStarted(int start) {
             return new SelectionEvent(
                     start, start + 1, EventType.SELECTION_STARTED,
@@ -458,7 +462,8 @@
          * @param start  the start word (inclusive) index of the selection
          * @param end  the end word (exclusive) index of the selection
          */
-        @UnsupportedAppUsage(trackingBug = 136637107)
+        @UnsupportedAppUsage(trackingBug = 136637107, maxTargetSdk = Build.VERSION_CODES.Q,
+                publicAlternatives = "See {@link android.view.textclassifier.TextClassifier}.")
         public static SelectionEvent selectionModified(int start, int end) {
             return new SelectionEvent(
                     start, end, EventType.SELECTION_MODIFIED,
@@ -474,7 +479,8 @@
          * @param classification  the TextClassification object returned by the TextClassifier that
          *      classified the selected text
          */
-        @UnsupportedAppUsage(trackingBug = 136637107)
+        @UnsupportedAppUsage(trackingBug = 136637107, maxTargetSdk = Build.VERSION_CODES.Q,
+                publicAlternatives = "See {@link android.view.textclassifier.TextClassifier}.")
         public static SelectionEvent selectionModified(
                 int start, int end, @NonNull TextClassification classification) {
             final String entityType = classification.getEntityCount() > 0
@@ -494,7 +500,8 @@
          * @param selection  the TextSelection object returned by the TextClassifier for the
          *      specified selection
          */
-        @UnsupportedAppUsage(trackingBug = 136637107)
+        @UnsupportedAppUsage(trackingBug = 136637107, maxTargetSdk = Build.VERSION_CODES.Q,
+                publicAlternatives = "See {@link android.view.textclassifier.TextClassifier}.")
         public static SelectionEvent selectionModified(
                 int start, int end, @NonNull TextSelection selection) {
             final boolean smartSelection = getSourceClassifier(selection.getId())
@@ -523,7 +530,8 @@
          * @param end  the end word (exclusive) index of the selection
          * @param actionType  the action that was performed on the selection
          */
-        @UnsupportedAppUsage(trackingBug = 136637107)
+        @UnsupportedAppUsage(trackingBug = 136637107, maxTargetSdk = Build.VERSION_CODES.Q,
+                publicAlternatives = "See {@link android.view.textclassifier.TextClassifier}.")
         public static SelectionEvent selectionAction(
                 int start, int end, @ActionType int actionType) {
             return new SelectionEvent(
@@ -541,7 +549,8 @@
          * @param classification  the TextClassification object returned by the TextClassifier that
          *      classified the selected text
          */
-        @UnsupportedAppUsage(trackingBug = 136637107)
+        @UnsupportedAppUsage(trackingBug = 136637107, maxTargetSdk = Build.VERSION_CODES.Q,
+                publicAlternatives = "See {@link android.view.textclassifier.TextClassifier}.")
         public static SelectionEvent selectionAction(
                 int start, int end, @ActionType int actionType,
                 @NonNull TextClassification classification) {
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 547aad6..5820f4b 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -19,7 +19,7 @@
 import android.annotation.DrawableRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
diff --git a/core/java/android/widget/CursorAdapter.java b/core/java/android/widget/CursorAdapter.java
index e250f63..600a34c 100644
--- a/core/java/android/widget/CursorAdapter.java
+++ b/core/java/android/widget/CursorAdapter.java
@@ -16,8 +16,8 @@
 
 package android.widget;
 
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.WorkerThread;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources;
 import android.database.ContentObserver;
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 0c593be..c1c1a6e 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -19,8 +19,8 @@
 import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.Widget;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java
index 5f15110..096e6ea 100644
--- a/core/java/android/widget/DatePickerSpinnerDelegate.java
+++ b/core/java/android/widget/DatePickerSpinnerDelegate.java
@@ -16,7 +16,7 @@
 
 package android.widget;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
diff --git a/core/java/android/widget/DateTimeView.java b/core/java/android/widget/DateTimeView.java
index 2864ad0..20a53c0 100644
--- a/core/java/android/widget/DateTimeView.java
+++ b/core/java/android/widget/DateTimeView.java
@@ -21,8 +21,8 @@
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 import static android.text.format.DateUtils.YEAR_IN_MILLIS;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index fa0af78..32f3acd 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -18,7 +18,7 @@
 
 import android.annotation.ColorInt;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.BlendMode;
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 3b6a009..0340cb3 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -21,10 +21,10 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
 import android.app.RemoteAction;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ClipData;
 import android.content.ClipData.Item;
 import android.content.Context;
@@ -139,6 +139,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * Helper class used by TextView to handle editable text views.
@@ -7062,11 +7063,11 @@
         private final List<ResolveInfo> mSupportedActivities = new ArrayList<>();
 
         private ProcessTextIntentActionsHandler(Editor editor) {
-            mEditor = Preconditions.checkNotNull(editor);
-            mTextView = Preconditions.checkNotNull(mEditor.mTextView);
-            mContext = Preconditions.checkNotNull(mTextView.getContext());
-            mPackageManager = Preconditions.checkNotNull(mContext.getPackageManager());
-            mPackageName = Preconditions.checkNotNull(mContext.getPackageName());
+            mEditor = Objects.requireNonNull(editor);
+            mTextView = Objects.requireNonNull(mEditor.mTextView);
+            mContext = Objects.requireNonNull(mTextView.getContext());
+            mPackageManager = Objects.requireNonNull(mContext.getPackageManager());
+            mPackageName = Objects.requireNonNull(mContext.getPackageName());
         }
 
         /**
diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java
index cae91fc..bdfb550 100644
--- a/core/java/android/widget/ExpandableListView.java
+++ b/core/java/android/widget/ExpandableListView.java
@@ -18,7 +18,7 @@
 
 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index 2c09185..0c0b349 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -23,7 +23,7 @@
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.annotation.StyleRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
diff --git a/core/java/android/widget/Filter.java b/core/java/android/widget/Filter.java
index 16f4ee2..06e6a5a 100644
--- a/core/java/android/widget/Filter.java
+++ b/core/java/android/widget/Filter.java
@@ -16,7 +16,7 @@
 
 package android.widget;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 69da911..92e9a96 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -20,7 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StyleRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Rect;
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index 64192aa..8c0061d 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -17,8 +17,8 @@
 package android.widget;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.Widget;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Rect;
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 8cda47d..f132197 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -31,7 +31,7 @@
 import static java.lang.Math.min;
 
 import android.annotation.IntDef;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 4e39a55..4a5e95e 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -18,7 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.TypedArray;
diff --git a/core/java/android/widget/HeaderViewListAdapter.java b/core/java/android/widget/HeaderViewListAdapter.java
index 10d50b8..eda7580 100644
--- a/core/java/android/widget/HeaderViewListAdapter.java
+++ b/core/java/android/widget/HeaderViewListAdapter.java
@@ -16,7 +16,7 @@
 
 package android.widget;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.database.DataSetObserver;
 import android.view.View;
 import android.view.ViewGroup;
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index ec685f5..b33660a 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -18,7 +18,7 @@
 
 import android.annotation.ColorInt;
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index d62b979..c2077384 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -20,7 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.ColorStateList;
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index a83e826..a796ba5 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -19,7 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index eb7a75b..8595fec 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -20,7 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StyleRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.database.DataSetObserver;
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 3a197e2..79ec680 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -19,7 +19,7 @@
 import android.annotation.IdRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.TypedArray;
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index f58b6d1..2924dd9 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -62,6 +62,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
 
 /**
  * Android magnifier widget. Can be used by any view which is attached to a window.
@@ -1154,7 +1155,7 @@
          * @param view the view this magnifier is attached to
          */
         public Builder(@NonNull View view) {
-            mView = Preconditions.checkNotNull(view);
+            mView = Objects.requireNonNull(view);
             applyDefaults();
         }
 
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index 65925b4..9c9baf3 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -16,7 +16,7 @@
 
 package android.widget;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 882e81a..e9e0c14 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -23,8 +23,8 @@
 import android.annotation.IntRange;
 import android.annotation.Px;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.Widget;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
diff --git a/core/java/android/widget/OverScroller.java b/core/java/android/widget/OverScroller.java
index e7a96be..1c33d80 100644
--- a/core/java/android/widget/OverScroller.java
+++ b/core/java/android/widget/OverScroller.java
@@ -16,7 +16,7 @@
 
 package android.widget;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.hardware.SensorManager;
 import android.util.Log;
diff --git a/core/java/android/widget/PopupMenu.java b/core/java/android/widget/PopupMenu.java
index b0c0c12..0ce9646 100644
--- a/core/java/android/widget/PopupMenu.java
+++ b/core/java/android/widget/PopupMenu.java
@@ -18,7 +18,7 @@
 
 import android.annotation.MenuRes;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.view.Gravity;
 import android.view.Menu;
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 3779779..bf696f5 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -18,13 +18,12 @@
 
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static android.view.WindowManager.LayoutParams
-        .PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.PixelFormat;
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 5cc0e0e..733a775 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -21,7 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.Px;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
diff --git a/core/java/android/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java
index c1a217c..ea39f6d 100644
--- a/core/java/android/widget/QuickContactBadge.java
+++ b/core/java/android/widget/QuickContactBadge.java
@@ -16,7 +16,7 @@
 
 package android.widget;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.AsyncQueryHandler;
 import android.content.ContentResolver;
 import android.content.Context;
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index 90bc0a3..71ccb59 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -19,7 +19,7 @@
 import android.annotation.IdRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
diff --git a/core/java/android/widget/RatingBar.java b/core/java/android/widget/RatingBar.java
index 3cf3d91..f946fe6 100644
--- a/core/java/android/widget/RatingBar.java
+++ b/core/java/android/widget/RatingBar.java
@@ -16,7 +16,7 @@
 
 package android.widget;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.drawable.shapes.RectShape;
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 253b6e1..d085eda 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -19,7 +19,7 @@
 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.ResourceId;
 import android.content.res.TypedArray;
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index a6304b1..d86766e 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -22,7 +22,6 @@
 import android.annotation.LayoutRes;
 import android.annotation.NonNull;
 import android.annotation.StyleRes;
-import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
 import android.app.ActivityOptions;
 import android.app.ActivityThread;
@@ -30,6 +29,7 @@
 import android.app.PendingIntent;
 import android.app.RemoteInput;
 import android.appwidget.AppWidgetHostView;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index efc5eb3..e58f08a 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -19,11 +19,11 @@
 import static android.widget.RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID;
 import static android.widget.RemoteViews.EXTRA_REMOTEADAPTER_ON_LIGHT_BACKGROUND;
 
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.WorkerThread;
 import android.app.IServiceConnection;
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/widget/ScrollBarDrawable.java b/core/java/android/widget/ScrollBarDrawable.java
index a5d3e45..80e17b5 100644
--- a/core/java/android/widget/ScrollBarDrawable.java
+++ b/core/java/android/widget/ScrollBarDrawable.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.PixelFormat;
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 1cc8ff6..3847d6b 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -18,7 +18,7 @@
 
 import android.annotation.ColorInt;
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
diff --git a/core/java/android/widget/Scroller.java b/core/java/android/widget/Scroller.java
index 229eaf0..6ed5b7e 100644
--- a/core/java/android/widget/Scroller.java
+++ b/core/java/android/widget/Scroller.java
@@ -16,7 +16,7 @@
 
 package android.widget;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.hardware.SensorManager;
 import android.os.Build;
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 89d9e97..15959c2 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -19,10 +19,10 @@
 import static android.widget.SuggestionsAdapter.getColumnString;
 
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.PendingIntent;
 import android.app.SearchManager;
 import android.app.SearchableInfo;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
diff --git a/core/java/android/widget/SeekBar.java b/core/java/android/widget/SeekBar.java
index e8cf1e8..5676881 100644
--- a/core/java/android/widget/SeekBar.java
+++ b/core/java/android/widget/SeekBar.java
@@ -16,7 +16,7 @@
 
 package android.widget;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.accessibility.AccessibilityNodeInfo;
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index d0f8093..4ef3f61 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -87,7 +87,7 @@
     private final SmartSelectSprite mSmartSelectSprite;
 
     SelectionActionModeHelper(@NonNull Editor editor) {
-        mEditor = Preconditions.checkNotNull(editor);
+        mEditor = Objects.requireNonNull(editor);
         mTextView = mEditor.getTextView();
         mTextClassificationHelper = new TextClassificationHelper(
                 mTextView.getContext(),
@@ -500,7 +500,7 @@
         private final LogAbandonRunnable mDelayedLogAbandon = new LogAbandonRunnable();
 
         SelectionTracker(TextView textView) {
-            mTextView = Preconditions.checkNotNull(textView);
+            mTextView = Objects.requireNonNull(textView);
             mLogger = new SelectionMetricsLogger(textView);
         }
 
@@ -703,7 +703,7 @@
         private String mText;
 
         SelectionMetricsLogger(TextView textView) {
-            Preconditions.checkNotNull(textView);
+            Objects.requireNonNull(textView);
             mEditTextLogger = textView.isTextEditable();
             mTokenIterator = SelectionSessionLogger.getTokenIterator(textView.getTextLocale());
         }
@@ -714,7 +714,7 @@
                 CharSequence text, int index,
                 @InvocationMethod int invocationMethod) {
             try {
-                Preconditions.checkNotNull(text);
+                Objects.requireNonNull(text);
                 Preconditions.checkArgumentInRange(index, 0, text.length(), "index");
                 if (mText == null || !mText.contentEquals(text)) {
                     mText = text.toString();
@@ -972,11 +972,11 @@
                 @NonNull Consumer<SelectionResult> selectionResultCallback,
                 @NonNull Supplier<SelectionResult> timeOutResultSupplier) {
             super(textView != null ? textView.getHandler() : null);
-            mTextView = Preconditions.checkNotNull(textView);
+            mTextView = Objects.requireNonNull(textView);
             mTimeOutDuration = timeOut;
-            mSelectionResultSupplier = Preconditions.checkNotNull(selectionResultSupplier);
-            mSelectionResultCallback = Preconditions.checkNotNull(selectionResultCallback);
-            mTimeOutResultSupplier = Preconditions.checkNotNull(timeOutResultSupplier);
+            mSelectionResultSupplier = Objects.requireNonNull(selectionResultSupplier);
+            mSelectionResultCallback = Objects.requireNonNull(selectionResultCallback);
+            mTimeOutResultSupplier = Objects.requireNonNull(timeOutResultSupplier);
             // Make a copy of the original text.
             mOriginalText = getText(mTextView).toString();
         }
@@ -1051,14 +1051,14 @@
         TextClassificationHelper(Context context, Supplier<TextClassifier> textClassifier,
                 CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
             init(textClassifier, text, selectionStart, selectionEnd, locales);
-            mContext = Preconditions.checkNotNull(context);
+            mContext = Objects.requireNonNull(context);
         }
 
         @UiThread
         public void init(Supplier<TextClassifier> textClassifier, CharSequence text,
                 int selectionStart, int selectionEnd, LocaleList locales) {
-            mTextClassifier = Preconditions.checkNotNull(textClassifier);
-            mText = Preconditions.checkNotNull(text).toString();
+            mTextClassifier = Objects.requireNonNull(textClassifier);
+            mText = Objects.requireNonNull(text).toString();
             mLastClassificationText = null; // invalidate.
             Preconditions.checkArgument(selectionEnd > selectionStart);
             mSelectionStart = selectionStart;
diff --git a/core/java/android/widget/SimpleAdapter.java b/core/java/android/widget/SimpleAdapter.java
index 15e1ffa..404b817 100644
--- a/core/java/android/widget/SimpleAdapter.java
+++ b/core/java/android/widget/SimpleAdapter.java
@@ -18,7 +18,7 @@
 
 import android.annotation.IdRes;
 import android.annotation.LayoutRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources;
 import android.net.Uri;
diff --git a/core/java/android/widget/SimpleCursorAdapter.java b/core/java/android/widget/SimpleCursorAdapter.java
index 77fe5d1..6277d5b 100644
--- a/core/java/android/widget/SimpleCursorAdapter.java
+++ b/core/java/android/widget/SimpleCursorAdapter.java
@@ -16,7 +16,7 @@
 
 package android.widget;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
diff --git a/core/java/android/widget/SlidingDrawer.java b/core/java/android/widget/SlidingDrawer.java
index 2ab2b24..9a4cfa1 100644
--- a/core/java/android/widget/SlidingDrawer.java
+++ b/core/java/android/widget/SlidingDrawer.java
@@ -17,7 +17,7 @@
 package android.widget;
 
 import android.R;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
diff --git a/core/java/android/widget/SmartSelectSprite.java b/core/java/android/widget/SmartSelectSprite.java
index 9a84f69..dc472e1 100644
--- a/core/java/android/widget/SmartSelectSprite.java
+++ b/core/java/android/widget/SmartSelectSprite.java
@@ -38,13 +38,12 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 
-import com.android.internal.util.Preconditions;
-
 import java.lang.annotation.Retention;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * A utility class for creating and animating the Smart Select animation.
@@ -75,7 +74,7 @@
         private final int mTextSelectionLayout;
 
         RectangleWithTextSelectionLayout(RectF rectangle, int textSelectionLayout) {
-            mRectangle = Preconditions.checkNotNull(rectangle);
+            mRectangle = Objects.requireNonNull(rectangle);
             mTextSelectionLayout = textSelectionLayout;
         }
 
@@ -342,7 +341,7 @@
                 context,
                 android.R.interpolator.fast_out_linear_in);
         mFillColor = highlightColor;
-        mInvalidator = Preconditions.checkNotNull(invalidator);
+        mInvalidator = Objects.requireNonNull(invalidator);
     }
 
     /**
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index 92fcea3..46fc09f 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -19,9 +19,9 @@
 import android.annotation.DrawableRes;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.Widget;
 import android.app.AlertDialog;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnClickListener;
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index fbd29ba..e1fd776 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -21,7 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StyleRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index 45e635ebe..a9a35115 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -18,8 +18,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.LocalActivityManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.TypedArray;
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index bd0d039..36abf3a 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -18,7 +18,7 @@
 
 import android.annotation.DrawableRes;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
index 2ae4389..5731e50 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -21,8 +21,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 43d9895..32d3fef 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -37,11 +37,11 @@
 import android.annotation.Size;
 import android.annotation.StringRes;
 import android.annotation.StyleRes;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.XmlRes;
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.app.assist.AssistStructure;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ClipData;
 import android.content.ClipDescription;
 import android.content.ClipboardManager;
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 8a5d531..51b1847 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -20,8 +20,8 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.Widget;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.icu.util.Calendar;
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 8f2133f..9bdb4c1 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -20,9 +20,9 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringRes;
-import android.annotation.UnsupportedAppUsage;
 import android.app.INotificationManager;
 import android.app.ITransientNotification;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index a21fb41..ea3f06b 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -24,8 +24,8 @@
 import android.annotation.StringRes;
 import android.annotation.StyleRes;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActionBar;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 40b0f13..36dafd5 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -17,8 +17,8 @@
 package android.widget;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
 import android.app.AlertDialog;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.res.Resources;
diff --git a/core/java/android/widget/ViewAnimator.java b/core/java/android/widget/ViewAnimator.java
index d36f343..90f61ca 100644
--- a/core/java/android/widget/ViewAnimator.java
+++ b/core/java/android/widget/ViewAnimator.java
@@ -18,7 +18,7 @@
 
 
 import android.annotation.AnimRes;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
diff --git a/core/java/android/widget/ViewFlipper.java b/core/java/android/widget/ViewFlipper.java
index b962298..2df9a78 100644
--- a/core/java/android/widget/ViewFlipper.java
+++ b/core/java/android/widget/ViewFlipper.java
@@ -17,7 +17,7 @@
 package android.widget;
 
 import android.annotation.IntRange;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/android/widget/ZoomControls.java b/core/java/android/widget/ZoomControls.java
index 7a5b7e8..f435533 100644
--- a/core/java/android/widget/ZoomControls.java
+++ b/core/java/android/widget/ZoomControls.java
@@ -16,8 +16,8 @@
 
 package android.widget;
 
-import android.annotation.UnsupportedAppUsage;
 import android.annotation.Widget;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
diff --git a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
index 33aa665..f9ba34e 100644
--- a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
+++ b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
@@ -15,14 +15,20 @@
  */
 package com.android.internal.app;
 
+import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
+import static android.view.accessibility.AccessibilityManager.ShortcutType;
+
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.Bundle;
 import android.provider.Settings;
 import android.view.LayoutInflater;
@@ -30,12 +36,17 @@
 import android.view.ViewGroup;
 import android.view.Window;
 import android.view.accessibility.AccessibilityManager;
+import android.widget.AdapterView;
 import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
+import android.widget.Switch;
 import android.widget.TextView;
 
 import com.android.internal.R;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -48,40 +59,74 @@
     private static final String MAGNIFICATION_COMPONENT_ID =
             "com.android.server.accessibility.MagnificationController";
 
-    private AccessibilityButtonTarget mMagnificationTarget = null;
-
-    private List<AccessibilityButtonTarget> mTargets = null;
-
+    private int mShortcutType;
+    private List<AccessibilityButtonTarget> mTargets = new ArrayList<>();
+    private List<AccessibilityButtonTarget> mReadyToBeDisabledTargets = new ArrayList<>();
     private AlertDialog mAlertDialog;
+    private TargetAdapter mTargetAdapter;
+
+    /**
+     * Annotation for different accessibilityService fragment UI type.
+     *
+     * {@code LEGACY} for displaying appearance aligned with sdk version Q accessibility service
+     * page, but only hardware shortcut allowed and under service in version Q or early.
+     * {@code INVISIBLE} for displaying appearance without switch bar.
+     * {@code INTUITIVE} for displaying appearance with version R accessibility design.
+     * {@code BOUNCE} for displaying appearance with pop-up action.
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            AccessibilityServiceFragmentType.LEGACY,
+            AccessibilityServiceFragmentType.INVISIBLE,
+            AccessibilityServiceFragmentType.INTUITIVE,
+            AccessibilityServiceFragmentType.BOUNCE,
+    })
+    public @interface AccessibilityServiceFragmentType {
+        int LEGACY = 0;
+        int INVISIBLE = 1;
+        int INTUITIVE = 2;
+        int BOUNCE = 3;
+    }
+
+    /**
+     * Annotation for different shortcut menu mode.
+     *
+     * {@code LAUNCH} for clicking list item to trigger the service callback.
+     * {@code EDIT} for clicking list item and save button to disable the service.
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            ShortcutMenuMode.LAUNCH,
+            ShortcutMenuMode.EDIT,
+    })
+    public @interface ShortcutMenuMode {
+        int LAUNCH = 0;
+        int EDIT = 1;
+    }
 
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         final TypedArray theme = getTheme().obtainStyledAttributes(android.R.styleable.Theme);
-        if (!theme.getBoolean(android.R.styleable.Theme_windowNoTitle, /* defValue= */false)) {
+        if (!theme.getBoolean(android.R.styleable.Theme_windowNoTitle, /* defValue= */ false)) {
             requestWindowFeature(Window.FEATURE_NO_TITLE);
         }
 
-        // TODO(b/146815874): Will replace it with white list services
-        mMagnificationTarget = new AccessibilityButtonTarget(this, MAGNIFICATION_COMPONENT_ID,
-                R.string.accessibility_magnification_chooser_text,
-                R.drawable.ic_accessibility_magnification);
-
-        // TODO(b/146815544): Will use shortcut type or button type to get the corresponding
-        //  services
-        mTargets = getServiceAccessibilityButtonTargets(this);
-        if (Settings.Secure.getInt(getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED, 0) == 1) {
-            mTargets.add(mMagnificationTarget);
-        }
+        mShortcutType = getIntent().getIntExtra(AccessibilityManager.EXTRA_SHORTCUT_TYPE,
+                ACCESSIBILITY_BUTTON);
+        mTargets.addAll(getServiceTargets(this, mShortcutType));
 
         // TODO(b/146815548): Will add title to separate which one type
+        mTargetAdapter = new TargetAdapter(mTargets);
         mAlertDialog = new AlertDialog.Builder(this)
-                .setAdapter(new TargetAdapter(),
-                        (dialog, position) -> onTargetSelected(mTargets.get(position)))
+                .setAdapter(mTargetAdapter, /* listener= */ null)
+                .setPositiveButton(
+                        getString(R.string.edit_accessibility_shortcut_menu_button),
+                        /* listener= */ null)
                 .setOnDismissListener(dialog -> finish())
                 .create();
+        mAlertDialog.setOnShowListener(dialog -> updateDialogListeners());
         mAlertDialog.show();
     }
 
@@ -91,41 +136,95 @@
         super.onDestroy();
     }
 
-    private static List<AccessibilityButtonTarget> getServiceAccessibilityButtonTargets(
-            @NonNull Context context) {
-        AccessibilityManager ams = (AccessibilityManager) context.getSystemService(
+    /**
+     * Gets the corresponding fragment type of a given accessibility service.
+     *
+     * @param accessibilityServiceInfo The accessibilityService's info.
+     * @return int from {@link AccessibilityServiceFragmentType}.
+     */
+    private static @AccessibilityServiceFragmentType int getAccessibilityServiceFragmentType(
+            AccessibilityServiceInfo accessibilityServiceInfo) {
+        final int targetSdk = accessibilityServiceInfo.getResolveInfo()
+                .serviceInfo.applicationInfo.targetSdkVersion;
+        final boolean requestA11yButton = (accessibilityServiceInfo.flags
+                & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
+
+        if (targetSdk <= Build.VERSION_CODES.Q) {
+            return AccessibilityServiceFragmentType.LEGACY;
+        }
+        return requestA11yButton
+                ? AccessibilityServiceFragmentType.INVISIBLE
+                : AccessibilityServiceFragmentType.INTUITIVE;
+    }
+
+    private static List<AccessibilityButtonTarget> getServiceTargets(@NonNull Context context,
+            @ShortcutType int shortcutType) {
+        final AccessibilityManager ams = (AccessibilityManager) context.getSystemService(
                 Context.ACCESSIBILITY_SERVICE);
-        List<AccessibilityServiceInfo> services = ams.getEnabledAccessibilityServiceList(
-                AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
-        if (services == null) {
+        final List<AccessibilityServiceInfo> installedServices =
+                ams.getInstalledAccessibilityServiceList();
+        if (installedServices == null) {
             return Collections.emptyList();
         }
 
-        ArrayList<AccessibilityButtonTarget> targets = new ArrayList<>(services.size());
-        for (AccessibilityServiceInfo info : services) {
+        final List<AccessibilityButtonTarget> targets = new ArrayList<>(installedServices.size());
+        for (AccessibilityServiceInfo info : installedServices) {
             if ((info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0) {
                 targets.add(new AccessibilityButtonTarget(context, info));
             }
         }
 
+        final List<String> requiredTargets = ams.getAccessibilityShortcutTargets(shortcutType);
+        targets.removeIf(target -> !requiredTargets.contains(target.getId()));
+
+        // TODO(b/146815874): Will replace it with white list services.
+        if (Settings.Secure.getInt(context.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED, 0) == 1) {
+            final AccessibilityButtonTarget magnificationTarget = new AccessibilityButtonTarget(
+                    context,
+                    MAGNIFICATION_COMPONENT_ID,
+                    R.string.accessibility_magnification_chooser_text,
+                    R.drawable.ic_accessibility_magnification,
+                    AccessibilityServiceFragmentType.INTUITIVE);
+            targets.add(magnificationTarget);
+        }
+
         return targets;
     }
 
-    private void onTargetSelected(AccessibilityButtonTarget target) {
-        Settings.Secure.putString(getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT, target.getId());
-        finish();
+    private static class ViewHolder {
+        ImageView mIconView;
+        TextView mLabelView;
+        FrameLayout mItemContainer;
+        ImageView mViewItem;
+        Switch mSwitchItem;
     }
 
-    private class TargetAdapter extends BaseAdapter {
+    private static class TargetAdapter extends BaseAdapter {
+        @ShortcutMenuMode
+        private int mShortcutMenuMode = ShortcutMenuMode.LAUNCH;
+        private List<AccessibilityButtonTarget> mButtonTargets;
+
+        TargetAdapter(List<AccessibilityButtonTarget> targets) {
+            this.mButtonTargets = targets;
+        }
+
+        void setShortcutMenuMode(int shortcutMenuMode) {
+            mShortcutMenuMode = shortcutMenuMode;
+        }
+
+        int getShortcutMenuMode() {
+            return mShortcutMenuMode;
+        }
+
         @Override
         public int getCount() {
-            return mTargets.size();
+            return mButtonTargets.size();
         }
 
         @Override
         public Object getItem(int position) {
-            return null;
+            return mButtonTargets.get(position);
         }
 
         @Override
@@ -135,36 +234,110 @@
 
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
-            LayoutInflater inflater = AccessibilityButtonChooserActivity.this.getLayoutInflater();
-            View root = inflater.inflate(R.layout.accessibility_button_chooser_item, parent, false);
-            final AccessibilityButtonTarget target = mTargets.get(position);
-            ImageView iconView = root.findViewById(R.id.accessibility_button_target_icon);
-            TextView labelView = root.findViewById(R.id.accessibility_button_target_label);
-            iconView.setImageDrawable(target.getDrawable());
-            labelView.setText(target.getLabel());
+            final Context context = parent.getContext();
+            ViewHolder holder;
+            if (convertView == null) {
+                convertView = LayoutInflater.from(context).inflate(
+                        R.layout.accessibility_button_chooser_item, parent, /* attachToRoot= */
+                        false);
+                holder = new ViewHolder();
+                holder.mIconView = convertView.findViewById(R.id.accessibility_button_target_icon);
+                holder.mLabelView = convertView.findViewById(
+                        R.id.accessibility_button_target_label);
+                holder.mItemContainer = convertView.findViewById(
+                        R.id.accessibility_button_target_item_container);
+                holder.mViewItem = convertView.findViewById(
+                        R.id.accessibility_button_target_view_item);
+                holder.mSwitchItem = convertView.findViewById(
+                        R.id.accessibility_button_target_switch_item);
+                convertView.setTag(holder);
+            } else {
+                holder = (ViewHolder) convertView.getTag();
+            }
 
-            // TODO(b/146815874): Need to get every service status to update UI
-            return root;
+            final AccessibilityButtonTarget target = mButtonTargets.get(position);
+            holder.mIconView.setImageDrawable(target.getDrawable());
+            holder.mLabelView.setText(target.getLabel());
+
+            updateActionItem(context, holder, target);
+
+            return convertView;
+        }
+
+        private void updateActionItem(@NonNull Context context,
+                @NonNull ViewHolder holder, AccessibilityButtonTarget target) {
+
+            switch (target.getFragmentType()) {
+                case AccessibilityServiceFragmentType.LEGACY:
+                case AccessibilityServiceFragmentType.INVISIBLE:
+                    updateLegacyOrInvisibleActionItemVisibility(context, holder);
+                    break;
+                case AccessibilityServiceFragmentType.INTUITIVE:
+                    updateIntuitiveActionItemVisibility(context, holder, target);
+                    break;
+                case AccessibilityServiceFragmentType.BOUNCE:
+                    updateBounceActionItemVisibility(context, holder);
+                    break;
+                default:
+                    throw new IllegalStateException("Unexpected fragment type");
+            }
+        }
+
+        private void updateLegacyOrInvisibleActionItemVisibility(@NonNull Context context,
+                @NonNull ViewHolder holder) {
+            final boolean isEditMenuMode = mShortcutMenuMode == ShortcutMenuMode.EDIT;
+
+            holder.mViewItem.setImageDrawable(context.getDrawable(R.drawable.ic_delete_item));
+            holder.mViewItem.setVisibility(View.VISIBLE);
+            holder.mSwitchItem.setVisibility(View.GONE);
+            holder.mItemContainer.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE);
+        }
+
+        private void updateIntuitiveActionItemVisibility(@NonNull Context context,
+                @NonNull ViewHolder holder, AccessibilityButtonTarget target) {
+            final boolean isEditMenuMode = mShortcutMenuMode == ShortcutMenuMode.EDIT;
+
+            holder.mViewItem.setImageDrawable(context.getDrawable(R.drawable.ic_delete_item));
+            holder.mViewItem.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE);
+            holder.mSwitchItem.setVisibility(isEditMenuMode ? View.GONE : View.VISIBLE);
+            holder.mSwitchItem.setChecked(!isEditMenuMode && isServiceEnabled(context, target));
+            holder.mItemContainer.setVisibility(View.VISIBLE);
+        }
+
+        private void updateBounceActionItemVisibility(@NonNull Context context,
+                @NonNull ViewHolder holder) {
+            final boolean isEditMenuMode = mShortcutMenuMode == ShortcutMenuMode.EDIT;
+
+            holder.mViewItem.setImageDrawable(
+                    isEditMenuMode ? context.getDrawable(R.drawable.ic_delete_item)
+                            : context.getDrawable(R.drawable.ic_open_in_new));
+            holder.mViewItem.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE);
+            holder.mSwitchItem.setVisibility(View.GONE);
+            holder.mItemContainer.setVisibility(View.VISIBLE);
         }
     }
 
     private static class AccessibilityButtonTarget {
-        public String mId;
-        public CharSequence mLabel;
-        public Drawable mDrawable;
-        // TODO(b/146815874): Will add fragment type and related functions
-        public AccessibilityButtonTarget(@NonNull Context context,
+        private String mId;
+        private CharSequence mLabel;
+        private Drawable mDrawable;
+        @AccessibilityServiceFragmentType
+        private int mFragmentType;
+
+        AccessibilityButtonTarget(@NonNull Context context,
                 @NonNull AccessibilityServiceInfo serviceInfo) {
             this.mId = serviceInfo.getComponentName().flattenToString();
             this.mLabel = serviceInfo.getResolveInfo().loadLabel(context.getPackageManager());
             this.mDrawable = serviceInfo.getResolveInfo().loadIcon(context.getPackageManager());
+            this.mFragmentType = getAccessibilityServiceFragmentType(serviceInfo);
         }
 
-        public AccessibilityButtonTarget(Context context, @NonNull String id, int labelResId,
-                int iconRes) {
+        AccessibilityButtonTarget(Context context, @NonNull String id, int labelResId,
+                int iconRes, @AccessibilityServiceFragmentType int fragmentType) {
             this.mId = id;
             this.mLabel = context.getText(labelResId);
             this.mDrawable = context.getDrawable(iconRes);
+            this.mFragmentType = fragmentType;
         }
 
         public String getId() {
@@ -178,5 +351,105 @@
         public Drawable getDrawable() {
             return mDrawable;
         }
+
+        public int getFragmentType() {
+            return mFragmentType;
+        }
+    }
+
+    private static boolean isServiceEnabled(@NonNull Context context,
+            AccessibilityButtonTarget target) {
+        final AccessibilityManager ams = (AccessibilityManager) context.getSystemService(
+                Context.ACCESSIBILITY_SERVICE);
+        final List<AccessibilityServiceInfo> enabledServices =
+                ams.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+
+        for (AccessibilityServiceInfo info : enabledServices) {
+            final String id = info.getComponentName().flattenToString();
+            if (id.equals(target.getId())) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private void onTargetSelected(AdapterView<?> parent, View view, int position, long id) {
+        Settings.Secure.putString(getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
+                mTargets.get(position).getId());
+        // TODO(b/146969684): notify accessibility button clicked.
+        mAlertDialog.dismiss();
+    }
+
+    private void onTargetDeleted(AdapterView<?> parent, View view, int position, long id) {
+        // TODO(b/147027236): Will discuss with UX designer what UX behavior about deleting item
+        //  is good for user.
+        mReadyToBeDisabledTargets.add(mTargets.get(position));
+        mTargets.remove(position);
+        mTargetAdapter.notifyDataSetChanged();
+    }
+
+    private void onCancelButtonClicked() {
+        resetAndUpdateTargets();
+
+        mTargetAdapter.setShortcutMenuMode(ShortcutMenuMode.LAUNCH);
+        mTargetAdapter.notifyDataSetChanged();
+
+        mAlertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE);
+        mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setText(
+                getString(R.string.edit_accessibility_shortcut_menu_button));
+
+        updateDialogListeners();
+    }
+
+    private void onEditButtonClicked() {
+        mTargetAdapter.setShortcutMenuMode(ShortcutMenuMode.EDIT);
+        mTargetAdapter.notifyDataSetChanged();
+
+        mAlertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setText(
+                getString(R.string.cancel_accessibility_shortcut_menu_button));
+        mAlertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.VISIBLE);
+        mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setText(
+                getString(R.string.save_accessibility_shortcut_menu_button));
+
+        updateDialogListeners();
+    }
+
+    private void onSaveButtonClicked() {
+        disableTargets();
+        resetAndUpdateTargets();
+
+        mTargetAdapter.setShortcutMenuMode(ShortcutMenuMode.LAUNCH);
+        mTargetAdapter.notifyDataSetChanged();
+
+        mAlertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE);
+        mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setText(
+                getString(R.string.edit_accessibility_shortcut_menu_button));
+
+        updateDialogListeners();
+    }
+
+    private void updateDialogListeners() {
+        final boolean isEditMenuMode =
+                mTargetAdapter.getShortcutMenuMode() == ShortcutMenuMode.EDIT;
+
+        mAlertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setOnClickListener(
+                view -> onCancelButtonClicked());
+        mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(
+                isEditMenuMode ? view -> onSaveButtonClicked() : view -> onEditButtonClicked());
+        mAlertDialog.getListView().setOnItemClickListener(
+                isEditMenuMode ? this::onTargetDeleted : this::onTargetSelected);
+    }
+
+    private void disableTargets() {
+        for (AccessibilityButtonTarget service : mReadyToBeDisabledTargets) {
+            // TODO(b/146967898): disable services.
+        }
+    }
+
+    private void resetAndUpdateTargets() {
+        mTargets.clear();
+        mTargets.addAll(getServiceTargets(this, mShortcutType));
     }
 }
diff --git a/core/java/com/android/internal/app/AlertActivity.java b/core/java/com/android/internal/app/AlertActivity.java
index 7307de5..cfbb273 100644
--- a/core/java/com/android/internal/app/AlertActivity.java
+++ b/core/java/com/android/internal/app/AlertActivity.java
@@ -16,9 +16,9 @@
 
 package com.android.internal.app;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
 import android.app.Dialog;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.DialogInterface;
 import android.os.Bundle;
 import android.view.KeyEvent;
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 0fd05c1..553721d7 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -18,14 +18,11 @@
 
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 
-import com.android.internal.R;
-
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.AlertDialog;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.database.Cursor;
 import android.graphics.drawable.Drawable;
@@ -33,7 +30,6 @@
 import android.os.Message;
 import android.text.Layout;
 import android.text.TextUtils;
-import android.text.method.LinkMovementMethod;
 import android.text.method.MovementMethod;
 import android.util.AttributeSet;
 import android.util.TypedValue;
@@ -46,7 +42,6 @@
 import android.view.ViewParent;
 import android.view.ViewStub;
 import android.view.Window;
-import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
@@ -63,6 +58,8 @@
 import android.widget.SimpleCursorAdapter;
 import android.widget.TextView;
 
+import com.android.internal.R;
+
 import java.lang.ref.WeakReference;
 
 public class AlertController {
diff --git a/core/java/com/android/internal/app/AssistUtils.java b/core/java/com/android/internal/app/AssistUtils.java
index f848309..22a2564 100644
--- a/core/java/com/android/internal/app/AssistUtils.java
+++ b/core/java/com/android/internal/app/AssistUtils.java
@@ -17,7 +17,7 @@
 package com.android.internal.app;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 06e96d5..1cc6d78 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -26,7 +26,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.prediction.AppPredictionContext;
@@ -34,6 +33,7 @@
 import android.app.prediction.AppPredictor;
 import android.app.prediction.AppTarget;
 import android.app.prediction.AppTargetEvent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ClipData;
 import android.content.ClipboardManager;
 import android.content.ComponentName;
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 46025aa..4e764fc 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -31,9 +31,11 @@
     // be kept in sync with frameworks/native/libs/binder/include/binder/IAppOpsService.h
     // and not be reordered
     int checkOperation(int code, int uid, String packageName);
-    int noteOperation(int code, int uid, String packageName, @nullable String featureId);
+    int noteOperation(int code, int uid, String packageName, @nullable String featureId,
+            boolean shouldCollectAsyncNotedOp, String message);
     int startOperation(IBinder clientId, int code, int uid, String packageName,
-            @nullable String featureId, boolean startIfModeDefault);
+            @nullable String featureId, boolean startIfModeDefault,
+            boolean shouldCollectAsyncNotedOp, String message);
     @UnsupportedAppUsage
     void finishOperation(IBinder clientId, int code, int uid, String packageName,
             @nullable String featureId);
@@ -41,8 +43,6 @@
     void stopWatchingMode(IAppOpsCallback callback);
     int permissionToOpCode(String permission);
     int checkAudioOperation(int code, int usage, int uid, String packageName);
-    void noteAsyncOp(@nullable String callingPackageName, int uid, @nullable String packageName,
-            int opCode, @nullable String featureId, String message);
     boolean shouldCollectNotes(int opCode);
     void setCameraAudioRestriction(int mode);
     // End of methods also called by native code.
@@ -50,7 +50,7 @@
 
     int noteProxyOperation(int code, int proxiedUid, String proxiedPackageName,
             String proxiedFeatureId, int proxyUid, String proxyPackageName,
-            String proxyFeatureId);
+            String proxyFeatureId, boolean shouldCollectAsyncNotedOp, String message);
 
     // Remaining methods are only used in Java.
     int checkPackage(int uid, String packageName);
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index a5f055f..9488e4f 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -20,12 +20,12 @@
 
 import android.annotation.Nullable;
 import android.annotation.StringRes;
-import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
 import android.app.ActivityTaskManager;
 import android.app.ActivityThread;
 import android.app.AppGlobals;
 import android.app.admin.DevicePolicyManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.IPackageManager;
diff --git a/core/java/com/android/internal/app/LocaleHelper.java b/core/java/com/android/internal/app/LocaleHelper.java
index e3d07aa..d418770e 100644
--- a/core/java/com/android/internal/app/LocaleHelper.java
+++ b/core/java/com/android/internal/app/LocaleHelper.java
@@ -17,7 +17,7 @@
 package com.android.internal.app;
 
 import android.annotation.IntRange;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.icu.text.ListFormatter;
 import android.icu.util.ULocale;
 import android.os.LocaleList;
diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java
index 7517424..3343593f 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -16,13 +16,11 @@
 
 package com.android.internal.app;
 
-import com.android.internal.R;
-
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
 import android.app.IActivityManager;
 import android.app.ListFragment;
 import android.app.backup.BackupManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -38,11 +36,13 @@
 import android.widget.ListView;
 import android.widget.TextView;
 
+import com.android.internal.R;
+
 import java.text.Collator;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
-import java.util.ArrayList;
 
 public class LocalePicker extends ListFragment {
     private static final String TAG = "LocalePicker";
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
index 49f77e1..1c5ca59 100644
--- a/core/java/com/android/internal/app/LocaleStore.java
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.app;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.LocaleList;
 import android.provider.Settings;
diff --git a/core/java/com/android/internal/app/NetInitiatedActivity.java b/core/java/com/android/internal/app/NetInitiatedActivity.java
index 9a802a9..89aa770 100644
--- a/core/java/com/android/internal/app/NetInitiatedActivity.java
+++ b/core/java/com/android/internal/app/NetInitiatedActivity.java
@@ -16,19 +16,19 @@
 
 package com.android.internal.app;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.AlertDialog;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.location.LocationManager;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
-import android.widget.Toast;
 import android.util.Log;
-import android.location.LocationManager;
+import android.widget.Toast;
 
 import com.android.internal.R;
 import com.android.internal.location.GpsNetInitiatedHandler;
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 8d3c572..b2417b2 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -24,7 +24,6 @@
 import android.annotation.Nullable;
 import android.annotation.StringRes;
 import android.annotation.UiThread;
-import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
@@ -32,6 +31,7 @@
 import android.app.VoiceInteractor.PickOptionRequest;
 import android.app.VoiceInteractor.PickOptionRequest.Option;
 import android.app.VoiceInteractor.Prompt;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java
index e71ee66..0cd1202 100644
--- a/core/java/com/android/internal/app/WindowDecorActionBar.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -16,28 +16,17 @@
 
 package com.android.internal.app;
 
-import com.android.internal.R;
-import com.android.internal.view.ActionBarPolicy;
-import com.android.internal.view.menu.MenuBuilder;
-import com.android.internal.view.menu.MenuPopupHelper;
-import com.android.internal.view.menu.SubMenuBuilder;
-import com.android.internal.widget.ActionBarContainer;
-import com.android.internal.widget.ActionBarContextView;
-import com.android.internal.widget.ActionBarOverlayLayout;
-import com.android.internal.widget.DecorToolbar;
-import com.android.internal.widget.ScrollingTabContainerView;
-
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActionBar;
 import android.app.Activity;
 import android.app.Dialog;
 import android.app.FragmentTransaction;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -58,6 +47,17 @@
 import android.widget.SpinnerAdapter;
 import android.widget.Toolbar;
 
+import com.android.internal.R;
+import com.android.internal.view.ActionBarPolicy;
+import com.android.internal.view.menu.MenuBuilder;
+import com.android.internal.view.menu.MenuPopupHelper;
+import com.android.internal.view.menu.SubMenuBuilder;
+import com.android.internal.widget.ActionBarContainer;
+import com.android.internal.widget.ActionBarContextView;
+import com.android.internal.widget.ActionBarOverlayLayout;
+import com.android.internal.widget.DecorToolbar;
+import com.android.internal.widget.ScrollingTabContainerView;
+
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index 6b76a0f..3682b7b 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -16,8 +16,8 @@
 
 package com.android.internal.content;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.Activity;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
diff --git a/core/java/com/android/internal/content/ReferrerIntent.java b/core/java/com/android/internal/content/ReferrerIntent.java
index 6d05f7e..6af03dd 100644
--- a/core/java/com/android/internal/content/ReferrerIntent.java
+++ b/core/java/com/android/internal/content/ReferrerIntent.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.content;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Intent;
 import android.os.Parcel;
 
diff --git a/core/java/com/android/internal/database/SortCursor.java b/core/java/com/android/internal/database/SortCursor.java
index 7fe809e..230a9b87 100644
--- a/core/java/com/android/internal/database/SortCursor.java
+++ b/core/java/com/android/internal/database/SortCursor.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.database;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.database.AbstractCursor;
 import android.database.Cursor;
 import android.database.DataSetObserver;
diff --git a/core/java/com/android/internal/infra/ServiceConnector.java b/core/java/com/android/internal/infra/ServiceConnector.java
index 857377a..e9d7d05 100644
--- a/core/java/com/android/internal/infra/ServiceConnector.java
+++ b/core/java/com/android/internal/infra/ServiceConnector.java
@@ -223,7 +223,7 @@
         private final @NonNull ServiceConnection mServiceConnection = this;
         private final @NonNull Runnable mTimeoutDisconnect = this;
 
-        private final @NonNull Context mContext;
+        protected final @NonNull Context mContext;
         private final @NonNull Intent mIntent;
         private final int mBindingFlags;
         private final int mUserId;
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index f916cf6..ed04fd8 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -15,7 +15,7 @@
  */
 package com.android.internal.logging;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.metrics.LogMaker;
 import android.os.Build;
diff --git a/core/java/com/android/internal/net/LegacyVpnInfo.java b/core/java/com/android/internal/net/LegacyVpnInfo.java
index 2ad9759..4eb7ded 100644
--- a/core/java/com/android/internal/net/LegacyVpnInfo.java
+++ b/core/java/com/android/internal/net/LegacyVpnInfo.java
@@ -16,8 +16,8 @@
 
 package com.android.internal.net;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.PendingIntent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.net.NetworkInfo;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index e6be549..f5a19fe 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -16,8 +16,8 @@
 
 package com.android.internal.net;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.PendingIntent;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index 940cc36..4bb012a 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -16,10 +16,9 @@
 
 package com.android.internal.net;
 
-import android.annotation.UnsupportedAppUsage;
-import android.os.Build;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.net.ProxyInfo;
-import android.net.Uri;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
diff --git a/core/java/com/android/internal/os/AndroidPrintStream.java b/core/java/com/android/internal/os/AndroidPrintStream.java
index fe23411..a6e41ff 100644
--- a/core/java/com/android/internal/os/AndroidPrintStream.java
+++ b/core/java/com/android/internal/os/AndroidPrintStream.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.Log;
 
 /**
diff --git a/core/java/com/android/internal/os/BaseCommand.java b/core/java/com/android/internal/os/BaseCommand.java
index 3d027c5..32442f0 100644
--- a/core/java/com/android/internal/os/BaseCommand.java
+++ b/core/java/com/android/internal/os/BaseCommand.java
@@ -17,7 +17,7 @@
 
 package com.android.internal.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.BasicShellCommandHandler;
 
 import java.io.PrintStream;
diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java
index b1fc369..b3ea118 100644
--- a/core/java/com/android/internal/os/BatterySipper.java
+++ b/core/java/com/android/internal/os/BatterySipper.java
@@ -15,7 +15,7 @@
  */
 package com.android.internal.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.BatteryStats.Uid;
 
 import java.util.List;
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index e85508e..b131ab8 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index d0a83c4..b3548b8 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -21,10 +21,10 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
 import android.bluetooth.BluetoothActivityEnergyInfo;
 import android.bluetooth.UidTraffic;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
diff --git a/core/java/com/android/internal/os/BinderInternal.java b/core/java/com/android/internal/os/BinderInternal.java
index 4901e1f..95c36ca 100644
--- a/core/java/com/android/internal/os/BinderInternal.java
+++ b/core/java/com/android/internal/os/BinderInternal.java
@@ -17,7 +17,7 @@
 package com.android.internal.os;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
diff --git a/core/java/com/android/internal/os/ClassLoaderFactory.java b/core/java/com/android/internal/os/ClassLoaderFactory.java
index d323498..a18943c 100644
--- a/core/java/com/android/internal/os/ClassLoaderFactory.java
+++ b/core/java/com/android/internal/os/ClassLoaderFactory.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Trace;
 
 import dalvik.system.DelegateLastClassLoader;
diff --git a/core/java/com/android/internal/os/FuseAppLoop.java b/core/java/com/android/internal/os/FuseAppLoop.java
index a22615b..ab0cc30 100644
--- a/core/java/com/android/internal/os/FuseAppLoop.java
+++ b/core/java/com/android/internal/os/FuseAppLoop.java
@@ -18,17 +18,19 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
-import android.os.ProxyFileDescriptorCallback;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Handler;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
+import android.os.ProxyFileDescriptorCallback;
 import android.system.ErrnoException;
 import android.system.OsConstants;
 import android.util.Log;
 import android.util.SparseArray;
+
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
+
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.Map;
diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java
index c8bfa1b..a11c815 100644
--- a/core/java/com/android/internal/os/HandlerCaller.java
+++ b/core/java/com/android/internal/os/HandlerCaller.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Handler;
 import android.os.Looper;
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 0faf962..3db8f4e 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -17,7 +17,7 @@
 package com.android.internal.os;
 
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index dcf8d28..f7b7742 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -16,9 +16,14 @@
 
 package com.android.internal.os;
 
-import static android.os.Process.*;
+import static android.os.Process.PROC_COMBINE;
+import static android.os.Process.PROC_OUT_FLOAT;
+import static android.os.Process.PROC_OUT_LONG;
+import static android.os.Process.PROC_OUT_STRING;
+import static android.os.Process.PROC_PARENS;
+import static android.os.Process.PROC_SPACE_TERM;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Process;
 import android.os.StrictMode;
 import android.os.SystemClock;
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index fa823c4..179828c 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -16,10 +16,10 @@
 
 package com.android.internal.os;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.app.ApplicationErrorReport;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.type.DefaultMimeMapFactory;
 import android.os.Build;
 import android.os.DeadObjectException;
diff --git a/core/java/com/android/internal/os/SomeArgs.java b/core/java/com/android/internal/os/SomeArgs.java
index d78bfac..003f610 100644
--- a/core/java/com/android/internal/os/SomeArgs.java
+++ b/core/java/com/android/internal/os/SomeArgs.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * Helper class for passing more arguments though a message
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 9c6a288..c91c661 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -23,7 +23,7 @@
 import static com.android.internal.os.ZygoteConnectionConstants.CONNECTION_TIMEOUT_MILLIS;
 import static com.android.internal.os.ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ApplicationInfo;
 import android.net.Credentials;
 import android.net.LocalSocket;
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 49b4cf8..7b6262b 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -19,8 +19,8 @@
 import static android.system.OsConstants.S_IRWXG;
 import static android.system.OsConstants.S_IRWXO;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.ApplicationLoaders;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.SharedLibraryInfo;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
diff --git a/core/java/com/android/internal/os/ZygoteSecurityException.java b/core/java/com/android/internal/os/ZygoteSecurityException.java
index 7e50cb8..8111483 100644
--- a/core/java/com/android/internal/os/ZygoteSecurityException.java
+++ b/core/java/com/android/internal/os/ZygoteSecurityException.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * Exception thrown when a security policy is violated.
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 29b148c..0170978 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -48,8 +48,8 @@
 import android.animation.ObjectAnimator;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
 import android.app.WindowConfiguration;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
diff --git a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
index 791c2d7..f07f667 100644
--- a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
+++ b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
@@ -16,9 +16,9 @@
 
 package com.android.internal.policy;
 
-import android.annotation.UnsupportedAppUsage;
 import android.app.KeyguardManager;
 import android.app.SearchManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
@@ -33,7 +33,6 @@
 import android.view.HapticFeedbackConstants;
 import android.view.KeyEvent;
 import android.view.View;
-import com.android.internal.policy.PhoneWindow;
 
 /**
  * @hide
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 9aa56f0..88a9cb0 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -32,10 +32,10 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
 import android.app.KeyguardManager;
 import android.app.SearchManager;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
diff --git a/core/java/com/android/internal/preference/YesNoPreference.java b/core/java/com/android/internal/preference/YesNoPreference.java
index 46d14a1..f878054 100644
--- a/core/java/com/android/internal/preference/YesNoPreference.java
+++ b/core/java/com/android/internal/preference/YesNoPreference.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.preference;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.os.Parcel;
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index c7ec2cd..cd69a02 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.ArraySet;
 
 import dalvik.system.VMRuntime;
diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java
index 121ae1a..7e3c171 100644
--- a/core/java/com/android/internal/util/AsyncChannel.java
+++ b/core/java/com/android/internal/util/AsyncChannel.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.util;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
diff --git a/core/java/com/android/internal/util/BitwiseInputStream.java b/core/java/com/android/internal/util/BitwiseInputStream.java
index 6ff67e9..ffae3ce 100644
--- a/core/java/com/android/internal/util/BitwiseInputStream.java
+++ b/core/java/com/android/internal/util/BitwiseInputStream.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.util;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * An object that provides bitwise incremental read access to a byte array.
diff --git a/core/java/com/android/internal/util/BitwiseOutputStream.java b/core/java/com/android/internal/util/BitwiseOutputStream.java
index cdd6f17..9f41508 100644
--- a/core/java/com/android/internal/util/BitwiseOutputStream.java
+++ b/core/java/com/android/internal/util/BitwiseOutputStream.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.util;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * An object that provides bitwise incremental write access to a byte array.
diff --git a/core/java/com/android/internal/util/CharSequences.java b/core/java/com/android/internal/util/CharSequences.java
index 6b6c43c..82ef200 100644
--- a/core/java/com/android/internal/util/CharSequences.java
+++ b/core/java/com/android/internal/util/CharSequences.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.util;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * {@link CharSequence} utility methods.
diff --git a/core/java/com/android/internal/util/FastMath.java b/core/java/com/android/internal/util/FastMath.java
index 35efe70..b7dbee5 100644
--- a/core/java/com/android/internal/util/FastMath.java
+++ b/core/java/com/android/internal/util/FastMath.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.util;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /**
  * Fast and loose math routines.
diff --git a/core/java/com/android/internal/util/FastPrintWriter.java b/core/java/com/android/internal/util/FastPrintWriter.java
index 981fbaa..63124de 100644
--- a/core/java/com/android/internal/util/FastPrintWriter.java
+++ b/core/java/com/android/internal/util/FastPrintWriter.java
@@ -16,7 +16,7 @@
 
 package com.android.internal.util;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.util.Log;
 import android.util.Printer;
 
diff --git a/core/java/com/android/internal/util/FastXmlSerializer.java b/core/java/com/android/internal/util/FastXmlSerializer.java
index 9f76aeb..94e07a8 100644
--- a/core/java/com/android/internal/util/FastXmlSerializer.java
+++ b/core/java/com/android/internal/util/FastXmlSerializer.java
@@ -16,9 +16,10 @@
 
 package com.android.internal.util;
 
+import android.compat.annotation.UnsupportedAppUsage;
+
 import org.xmlpull.v1.XmlSerializer;
 
-import android.annotation.UnsupportedAppUsage;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 6095ffa..f5e2a52 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -5,7 +5,7 @@
 #include "SkShader.h"
 #include "SkBlendMode.h"
 #include "core_jni_helpers.h"
-#include "src/shaders/SkRTShader.h"
+#include "include/effects/SkRuntimeEffect.h"
 
 #include <jni.h>
 
@@ -214,14 +214,14 @@
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
 static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderFactory, jlong matrixPtr,
-        jbyteArray inputs, jlong colorSpaceHandle) {
-    SkRuntimeShaderFactory* factory = reinterpret_cast<SkRuntimeShaderFactory*>(shaderFactory);
+        jbyteArray inputs, jlong colorSpaceHandle, jboolean isOpaque) {
+    SkRuntimeEffect* effect = reinterpret_cast<SkRuntimeEffect*>(shaderFactory);
     AutoJavaByteArray arInputs(env, inputs);
 
     sk_sp<SkData> fData;
     fData = SkData::MakeWithCopy(arInputs.ptr(), arInputs.length());
     const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
-    sk_sp<SkShader> shader = factory->make(fData, matrix);
+    sk_sp<SkShader> shader = effect->makeShader(fData, nullptr, 0, matrix, isOpaque == JNI_TRUE);
     ThrowIAE_IfNull(env, shader);
 
     return reinterpret_cast<jlong>(shader.release());
@@ -229,24 +229,22 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-static jlong RuntimeShader_createShaderFactory(JNIEnv* env, jobject, jstring sksl,
-        jboolean isOpaque) {
+static jlong RuntimeShader_createShaderFactory(JNIEnv* env, jobject, jstring sksl) {
     ScopedUtfChars strSksl(env, sksl);
-    SkRuntimeShaderFactory* shaderFactory = new SkRuntimeShaderFactory(SkString(strSksl.c_str()),
-            isOpaque == JNI_TRUE);
-    ThrowIAE_IfNull(env, shaderFactory);
+    sk_sp<SkRuntimeEffect> effect = std::get<0>(SkRuntimeEffect::Make(SkString(strSksl.c_str())));
+    ThrowIAE_IfNull(env, effect);
 
-    return reinterpret_cast<jlong>(shaderFactory);
+    return reinterpret_cast<jlong>(effect.release());
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-static void RuntimeShader_delete(SkRuntimeShaderFactory* shaderFactory) {
-    delete shaderFactory;
+static void Effect_safeUnref(SkRuntimeEffect* effect) {
+    SkSafeUnref(effect);
 }
 
 static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) {
-    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&RuntimeShader_delete));
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Effect_safeUnref));
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
@@ -282,8 +280,8 @@
 
 static const JNINativeMethod gRuntimeShaderMethods[] = {
     { "nativeGetFinalizer",   "()J",    (void*)RuntimeShader_getNativeFinalizer },
-    { "nativeCreate",     "(JJ[BJ)J",  (void*)RuntimeShader_create     },
-    { "nativeCreateShaderFactory",     "(Ljava/lang/String;Z)J",
+    { "nativeCreate",     "(JJ[BJZ)J",  (void*)RuntimeShader_create     },
+    { "nativeCreateShaderFactory",     "(Ljava/lang/String;)J",
       (void*)RuntimeShader_createShaderFactory     },
 };
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7719165..fd4e7c6 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -932,6 +932,14 @@
     <permission android:name="android.permission.WRITE_OBB"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Allows an application a broad access to external storage in scoped storage.
+         Intended to be used by few apps that need to manage files on behalf of the users.
+         <p>Protection level: signature|appop
+         <p>This protection level is temporary and will most likely be changed to |preinstalled -->
+    <permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
+        android:permissionGroup="android.permission-group.UNDEFINED"
+        android:protectionLevel="signature|appop" />
+
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the device location                          -->
     <!-- ====================================================================== -->
@@ -1615,6 +1623,12 @@
     <permission android:name="android.permission.REQUEST_NETWORK_SCORES"
         android:protectionLevel="signature|setup" />
 
+    <!-- @SystemApi @hide Allows applications to toggle airplane mode.
+         <p>Not for use by third-party or privileged applications.
+    -->
+    <permission android:name="android.permission.NETWORK_AIRPLANE_MODE"
+        android:protectionLevel="signature" />
+
     <!-- Allows network stack services (Connectivity and Wifi) to coordinate
          <p>Not for use by third-party or privileged applications.
          @SystemApi
@@ -3591,6 +3605,11 @@
     <permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows an application to start and stop one time permission sessions
+    @hide -->
+    <permission android:name="android.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS"
+                android:protectionLevel="signature|installer" />
+
     <!-- @SystemApi Allows an application to manage the holders of a role.
          @hide
          STOPSHIP b/145526313: Remove wellbeing protection flag from MANAGE_ROLE_HOLDERS. -->
diff --git a/core/res/res/drawable/ic_delete_item.xml b/core/res/res/drawable/ic_delete_item.xml
new file mode 100644
index 0000000..8a398a4
--- /dev/null
+++ b/core/res/res/drawable/ic_delete_item.xml
@@ -0,0 +1,26 @@
+<!--
+    Copyright (C) 2020 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"
+      android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/core/res/res/drawable/ic_open_in_new.xml b/core/res/res/drawable/ic_open_in_new.xml
new file mode 100644
index 0000000..67378c8
--- /dev/null
+++ b/core/res/res/drawable/ic_open_in_new.xml
@@ -0,0 +1,26 @@
+<!--
+    Copyright (C) 2020 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:pathData="M19,19H5V5h7V3H5c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2v-7h-2v7zM14,3v2h3.59l-9.83,9.83 1.41,1.41L19,6.41V10h2V3h-7z"
+      android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/core/res/res/layout/accessibility_button_chooser_item.xml b/core/res/res/layout/accessibility_button_chooser_item.xml
index fddca5a..1edd2cd 100644
--- a/core/res/res/layout/accessibility_button_chooser_item.xml
+++ b/core/res/res/layout/accessibility_button_chooser_item.xml
@@ -21,10 +21,10 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:gravity="center"
-    android:paddingBottom="12dp"
-    android:paddingEnd="16dp"
     android:paddingStart="16dp"
-    android:paddingTop="12dp">
+    android:paddingEnd="16dp"
+    android:paddingTop="12dp"
+    android:paddingBottom="12dp">
 
     <ImageView
         android:id="@+id/accessibility_button_target_icon"
@@ -39,5 +39,26 @@
         android:layout_marginStart="8dp"
         android:layout_weight="1"
         android:textColor="?attr/textColorPrimary"/>
+
+    <FrameLayout
+        android:id="@+id/accessibility_button_target_item_container"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:minWidth="56dp">
+
+        <ImageView
+            android:id="@+id/accessibility_button_target_view_item"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"/>
+
+        <Switch android:id="@+id/accessibility_button_target_switch_item"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:background="@null"
+                android:clickable="false"
+                android:focusable="false"/>
+    </FrameLayout>
 </LinearLayout>
 
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index eb1f553..68708d35 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -440,7 +440,7 @@
     <string name="permlab_callPhone" msgid="1798582257194643320">"اتصال مباشر بأرقام الهواتف"</string>
     <string name="permdesc_callPhone" msgid="5439809516131609109">"للسماح للتطبيق بطلب أرقام هاتفية بدون تدخل منك. وقد يؤدي ذلك إلى تحمل رسوم غير متوقعة أو إجراء مكالمات غير متوقعة. ومن الجدير بالذكر أن ذلك لا يتيح للتطبيق الاتصال بأرقام الطوارئ. وقد تؤدي التطبيقات الضارة إلى تحملك تكاليف مالية من خلال إجراء مكالمات بدون موافقة منك."</string>
     <string name="permlab_accessImsCallService" msgid="442192920714863782">"الوصول إلى خدمة الاتصال عبر الرسائل الفورية"</string>
-    <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"للسماح للتطبيق باستخدام خدمة الرسائل الفورية لإجراء المكالمات دون تدخل منك."</string>
+    <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"للسماح للتطبيق باستخدام خدمة الرسائل الفورية لإجراء المكالمات بدون تدخل منك."</string>
     <string name="permlab_readPhoneState" msgid="8138526903259297969">"قراءة حالة الهاتف والهوية"</string>
     <string name="permdesc_readPhoneState" msgid="7229063553502788058">"للسماح للتطبيق بالدخول إلى ميزات الهاتف في الجهاز. ويتيح هذا الإذن للتطبيق تحديد رقم الهاتف ومعرّفات الجهاز، وما إذا كانت هناك مكالمة نشطة والرقم البعيد الذي تم الاتصال به في المكالمة."</string>
     <string name="permlab_manageOwnCalls" msgid="9033349060307561370">"توجيه المكالمات من خلال النظام"</string>
@@ -1283,7 +1283,7 @@
     <string name="heavy_weight_switcher_text" msgid="6814316627367160126">"للحصول على أداء أفضل، يمكن فتح لعبة واحدة فقط من هذه الألعاب في كل مرة."</string>
     <string name="old_app_action" msgid="725331621042848590">"الرجوع إلى <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_action" msgid="547772182913269801">"فتح <xliff:g id="NEW_APP">%1$s</xliff:g>"</string>
-    <string name="new_app_description" msgid="1958903080400806644">"سيتم إغلاق <xliff:g id="OLD_APP">%1$s</xliff:g> من دون حفظ"</string>
+    <string name="new_app_description" msgid="1958903080400806644">"سيتم إغلاق <xliff:g id="OLD_APP">%1$s</xliff:g> بدون حفظ"</string>
     <string name="dump_heap_notification" msgid="5316644945404825032">"لقد تجاوزت <xliff:g id="PROC">%1$s</xliff:g> حد الذاكرة."</string>
     <string name="dump_heap_ready_notification" msgid="2302452262927390268">"نَسْخ الذاكرة <xliff:g id="PROC">%1$s</xliff:g> جاهز"</string>
     <string name="dump_heap_notification_detail" msgid="8431586843001054050">"تم جمع مقدار كبير من بيانات الذاكرة. انقر للمشاركة."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 6928a14..612854c 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1855,11 +1855,9 @@
     <string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g> से कनेक्ट किया गया"</string>
     <string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"फ़ाइलें देखने के लिए टैप करें"</string>
     <string name="pin_target" msgid="8036028973110156895">"पिन करें"</string>
-    <!-- no translation found for pin_specific_target (7824671240625957415) -->
-    <skip />
+    <string name="pin_specific_target" msgid="7824671240625957415">"<xliff:g id="LABEL">%1$s</xliff:g> को पिन करें"</string>
     <string name="unpin_target" msgid="3963318576590204447">"अनपिन करें"</string>
-    <!-- no translation found for unpin_specific_target (3859828252160908146) -->
-    <skip />
+    <string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> को अनपिन करें"</string>
     <string name="app_info" msgid="6113278084877079851">"ऐप्लिकेशन की जानकारी"</string>
     <string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="demo_starting_message" msgid="6577581216125805905">"डेमो प्रारंभ हो रहा है…"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index aa28bf2..3e23679 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -665,7 +665,7 @@
     <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"Sletter denne brukerens data på dette nettbrettet uten advarsel."</string>
     <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2293713284515865200">"Tøm dataene til denne brukeren på denne Android TV-enheten uten advarsel."</string>
     <string name="policydesc_wipeData_secondaryUser" product="default" msgid="2788325512167208654">"Sletter denne brukerens data på denne telefonen uten advarsel."</string>
-    <string name="policylab_setGlobalProxy" msgid="215332221188670221">"Angi enhetens globale mellomtjener"</string>
+    <string name="policylab_setGlobalProxy" msgid="215332221188670221">"Angi enhetens globale proxy-tjener"</string>
     <string name="policydesc_setGlobalProxy" msgid="7149665222705519604">"Angir den globale proxy-tjeneren på enheten som skal brukes når regelen er aktivert. Bare eieren av enheten kan angi den globale proxy-tjeneren."</string>
     <string name="policylab_expirePassword" msgid="6015404400532459169">"Angi utløpstid for skjermlås"</string>
     <string name="policydesc_expirePassword" msgid="9136524319325960675">"Endrer hvor ofte PIN-koden, passordet eller mønsteret til skjermlåsen skal byttes."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index be173dd..7aa91f7 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -497,10 +497,8 @@
     <string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"Aplikaciji omogoča ogled konfiguracije Bluetootha tabličnega računalnika ter vzpostavljanje in sprejemanje povezave s seznanjenimi napravami."</string>
     <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"Aplikaciji dovoljuje ogled konfiguracije vmesnika Bluetooth v napravi Android TV ter ustvarjanje in sprejemanje povezav s seznanjenimi napravami."</string>
     <string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"Aplikaciji omogoča ogled konfiguracije Bluetootha telefona ter ustvarjanje in sprejemanje povezave s seznanjenimi napravami."</string>
-    <!-- no translation found for permlab_preferredPaymentInfo (5274423844767445054) -->
-    <skip />
-    <!-- no translation found for permdesc_preferredPaymentInfo (8583552469807294967) -->
-    <skip />
+    <string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"Podatki o prednostni storitvi za plačevanje prek povezave NFC"</string>
+    <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"Aplikaciji omogoča pridobivanje podatkov o prednostni storitvi za plačevanje prek povezave NFC, kot so registrirani pripomočki in cilj preusmeritve."</string>
     <string name="permlab_nfc" msgid="1904455246837674977">"nadzor nad komunikacijo s tehnologijo bližnjega polja"</string>
     <string name="permdesc_nfc" msgid="8352737680695296741">"Podpira komunikacijo med računalnikom in oznakami, karticami in bralniki komunikacije s tehnologijo bližnjega polja."</string>
     <string name="permlab_disableKeyguard" msgid="3605253559020928505">"onemogočanje zaklepanja zaslona"</string>
@@ -1663,12 +1661,6 @@
     <string name="accessibility_shortcut_enabling_service" msgid="6141620395915529473">"Bližnjica funkcij za ljudi s posebnimi potrebami je vklopila <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="1287340429965172651">"Bližnjica funkcij za ljudi s posebnimi potrebami je izklopila <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Za uporabo storitve <xliff:g id="SERVICE_NAME">%1$s</xliff:g> pritisnite obe tipki za glasnost in ju pridržite tri sekunde"</string>
-    <string name="accessibility_button_prompt_text" msgid="1634298854002673171">"Izberite storitev, ki jo želite uporabljati, ko se dotaknete gumba za funkcije za ljudi s posebnimi potrebami:"</string>
-    <string name="accessibility_gesture_prompt_text" msgid="3271927619707898924">"Izberite storitev, ki jo želite zagnati s potezo za ljudi s posebnimi potrebami (vlečenje z dvema prstoma z dna zaslona navzgor):"</string>
-    <string name="accessibility_gesture_3finger_prompt_text" msgid="218295923313037542">"Izberite storitev, ki jo želite zagnati s potezo za ljudi s posebnimi potrebami (vlečenje s tremi prsti z dna zaslona navzgor):"</string>
-    <string name="accessibility_button_instructional_text" msgid="8523635009916665153">"Če želite preklopiti med storitvami, pridržite gumb za funkcije za ljudi s posebnimi potrebami."</string>
-    <string name="accessibility_gesture_instructional_text" msgid="927882482331885974">"Če želite preklopiti med storitvami, z dvema prstoma povlecite navzgor in pridržite."</string>
-    <string name="accessibility_gesture_3finger_instructional_text" msgid="7527523742771203377">"Če želite preklopiti med storitvami, s tremi prsti povlecite navzgor in pridržite."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Povečava"</string>
     <string name="user_switched" msgid="7249833311585228097">"Trenutni uporabnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Preklop na uporabnika <xliff:g id="NAME">%1$s</xliff:g> …"</string>
@@ -1927,11 +1919,9 @@
     <string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"Vzpostavljena povezava z napravo <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
     <string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"Dotaknite se, če si želite ogledati datoteke"</string>
     <string name="pin_target" msgid="8036028973110156895">"Pripenjanje"</string>
-    <!-- no translation found for pin_specific_target (7824671240625957415) -->
-    <skip />
+    <string name="pin_specific_target" msgid="7824671240625957415">"Pripni aplikacijo <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="unpin_target" msgid="3963318576590204447">"Odpenjanje"</string>
-    <!-- no translation found for unpin_specific_target (3859828252160908146) -->
-    <skip />
+    <string name="unpin_specific_target" msgid="3859828252160908146">"Odpni aplikacijo <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="app_info" msgid="6113278084877079851">"Podatki o aplikacijah"</string>
     <string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="demo_starting_message" msgid="6577581216125805905">"Začenjanje predstavitve …"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index d01e8e7..2cc42d7 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -491,8 +491,8 @@
     <string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"允許應用程式查看平板電腦的藍牙設定,以及建立和接受與其他配對裝置的連線。"</string>
     <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"允許應用程式查看 Android TV 裝置的藍牙設定,以及建立和接受與其他配對裝置的連線。"</string>
     <string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"允許應用程式查看手機的藍牙設定,以及建立和接受與其他配對裝置的連線。"</string>
-    <string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"首選 NFC 付款服務資訊"</string>
-    <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"允許應用程式取得首選 NFC 付款服務的資訊 (如已註冊的付款輔助和最終付款對象)。"</string>
+    <string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"由用戶允許授權的 NFC 付款服務資訊"</string>
+    <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"允許應用程式取得由用戶允許授權的 NFC 付款服務資訊 (如已註冊的付款輔助功能和最終付款對象)。"</string>
     <string name="permlab_nfc" msgid="1904455246837674977">"控制近距離無線通訊"</string>
     <string name="permdesc_nfc" msgid="8352737680695296741">"允許應用程式使用近距離無線通訊 (NFC) 標記、卡片及讀取程式進行通訊。"</string>
     <string name="permlab_disableKeyguard" msgid="3605253559020928505">"停用螢幕上鎖"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 38d3e9c..9c08728 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3469,6 +3469,8 @@
              device -->
         <attr name="isVrOnly" format="boolean"/>
         <attr name="__removed2" format="boolean" />
+        <!-- Specifies whether the IME supports showing inline suggestions. -->
+        <attr name="supportsInlineSuggestions" format="boolean" />
     </declare-styleable>
 
     <!-- This is the subtype of InputMethod. Subtype can describe locales (for example, en_US and
@@ -8177,6 +8179,9 @@
         <!-- Fully qualified class name of an activity that allows the user to modify
              the settings for this service. -->
         <attr name="settingsActivity" />
+
+        <!-- Specifies whether the AutofillService supports inline suggestions-->
+        <attr name="supportsInlineSuggestions" format="boolean" />
     </declare-styleable>
 
     <!-- Use <code>compatibility-package</code> as a child tag of <code>autofill-service</code>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 85f7d61..6435cdd 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1533,7 +1533,8 @@
          <code>com.google.app.<em>appname</em></code>
 
          <p>Inside of the manifest tag, may appear the following tags
-         in any order: {@link #AndroidManifestPermission permission},
+         in any order: {@link #AndroidManifestFeature feature},
+         {@link #AndroidManifestPermission permission},
          {@link #AndroidManifestPermissionGroup permission-group},
          {@link #AndroidManifestPermissionTree permission-tree},
          {@link #AndroidManifestUsesSdk uses-sdk},
@@ -1763,6 +1764,29 @@
              The default value is {@code false}. -->
         <attr name="crossProfile" format="boolean" />
     </declare-styleable>
+
+    <!-- The <code>feature</code> tag declares a feature. A feature is a part of an app. E.g.
+    photo sharing app might include a direct messaging component.
+
+    <p>This appears as a child tag of the root {@link #AndroidManifest manifest} tag.
+
+    <p>In case this feature inherits from another feature, this tag can contain one or multiple
+    {@link #AndroidManifestFeatureInheritFrom inherit-from} tags. -->
+    <declare-styleable name="AndroidManifestFeature" parent="AndroidManifest">
+        <!-- Required identifier for a feature. Can be passed to
+        {@link android.content.Context#createFeatureContext} to create a context for this feature
+        -->
+        <attr name="featureId" format="string" />
+        <!-- Required user visible label for a feature. -->
+        <attr name="label" format="string" />
+    </declare-styleable>
+
+    <!-- Declares previously declared features this feature inherits from. -->
+    <declare-styleable name="AndroidManifestFeatureInheritFrom" parent="AndroidManifestFeature">
+        <!-- Identifier of the feature this feature inherits from -->
+        <attr name="featureId" format="string" />
+    </declare-styleable>
+
     <!-- The <code>permission</code> tag declares a security permission that can be
          used to control access from other packages to specific components or
          features in your package (or other packages).  See the
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 0b63518..d12d069 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3004,6 +3004,9 @@
       <public name="resourcesMap" />
       <public name="animatedImageDrawable"/>
       <public name="htmlDescription"/>
+      <public name="preferMinimalPostProcessing"/>
+      <public name="featureId" />
+      <public name="supportsInlineSuggestions" />
     </public-group>
 
     <public-group type="drawable" first-id="0x010800b5">
@@ -3049,10 +3052,6 @@
       <public name="accessibilitySystemActionLockScreen" />
       <public name="accessibilitySystemActionTakeScreenshot" />
     </public-group>
-
-    <public-group type="attr" first-id="0x0101060c">
-      <public name="preferMinimalPostProcessing"/>
-    </public-group>
   <!-- ===============================================================
        DO NOT ADD UN-GROUPED ITEMS HERE
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ed744ba..66267d1 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4354,6 +4354,18 @@
         You can change the feature in Settings > Accessibility.
     </string>
 
+    <!-- Text in button that edit the accessibility shortcut menu. [CHAR LIMIT=100] -->
+    <string name="accessibility_shortcut_menu_button">Empty</string>
+
+    <!-- Text in button that edit the accessibility shortcut menu. [CHAR LIMIT=100] -->
+    <string name="edit_accessibility_shortcut_menu_button">Edit</string>
+
+    <!-- Text in button that save the accessibility shortcut menu changed status. [CHAR LIMIT=100] -->
+    <string name="save_accessibility_shortcut_menu_button">Save</string>
+
+    <!-- Text in button that cancel the accessibility shortcut menu changed status. [CHAR LIMIT=100] -->
+    <string name="cancel_accessibility_shortcut_menu_button">Cancel</string>
+
     <!-- Text in button that turns off the accessibility shortcut -->
     <string name="disable_accessibility_shortcut">Turn off Shortcut</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a00296c..356ec2b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3207,10 +3207,19 @@
   <java-symbol type="layout" name="accessibility_button_chooser_item" />
   <java-symbol type="id" name="accessibility_button_target_icon" />
   <java-symbol type="id" name="accessibility_button_target_label" />
+  <java-symbol type="id" name="accessibility_button_target_item_container" />
+  <java-symbol type="id" name="accessibility_button_target_view_item" />
+  <java-symbol type="id" name="accessibility_button_target_switch_item" />
   <java-symbol type="string" name="accessibility_magnification_chooser_text" />
+  <java-symbol type="string" name="edit_accessibility_shortcut_menu_button" />
+  <java-symbol type="string" name="save_accessibility_shortcut_menu_button" />
+  <java-symbol type="string" name="cancel_accessibility_shortcut_menu_button" />
 
   <java-symbol type="drawable" name="ic_accessibility_magnification" />
 
+  <java-symbol type="drawable" name="ic_delete_item" />
+  <java-symbol type="drawable" name="ic_open_in_new" />
+
   <!-- com.android.internal.widget.RecyclerView -->
   <java-symbol type="id" name="item_touch_helper_previous_elevation"/>
   <java-symbol type="dimen" name="item_touch_helper_max_drag_scroll_per_frame"/>
diff --git a/core/tests/coretests/res/xml/ime_meta_inline_suggestions.xml b/core/tests/coretests/res/xml/ime_meta_inline_suggestions.xml
new file mode 100644
index 0000000..e67bf63
--- /dev/null
+++ b/core/tests/coretests/res/xml/ime_meta_inline_suggestions.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.
+-->
+
+<input-method
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:settingsActivity="com.android.inputmethod.latin.settings.SettingsActivity"
+    android:supportsInlineSuggestions="true"
+>
+    <subtype
+        android:label="subtype1"
+        android:imeSubtypeLocale="en_US"
+        android:imeSubtypeMode="keyboard" />
+</input-method>
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
index f24e232..8718b95 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
@@ -54,10 +54,12 @@
         final InputMethodInfo imi = buildInputMethodForTest(R.xml.ime_meta);
 
         assertThat(imi.supportsSwitchingToNextInputMethod(), is(false));
+        assertThat(imi.isInlineSuggestionsEnabled(), is(false));
 
         final InputMethodInfo clone = cloneViaParcel(imi);
 
         assertThat(clone.supportsSwitchingToNextInputMethod(), is(false));
+        assertThat(imi.isInlineSuggestionsEnabled(), is(false));
     }
 
     @Test
@@ -72,6 +74,17 @@
     }
 
     @Test
+    public void testInlineSuggestionsEnabled() throws Exception {
+        final InputMethodInfo imi = buildInputMethodForTest(R.xml.ime_meta_inline_suggestions);
+
+        assertThat(imi.isInlineSuggestionsEnabled(), is(true));
+
+        final InputMethodInfo clone = cloneViaParcel(imi);
+
+        assertThat(clone.isInlineSuggestionsEnabled(), is(true));
+    }
+
+    @Test
     public void testIsVrOnly() throws Exception {
         final InputMethodInfo imi = buildInputMethodForTest(R.xml.ime_meta_vr_only);
 
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index c3ef1c8..fbe4c1a 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -1022,23 +1022,11 @@
 
     @Test
     public void testSelectionMetricsLogger_abandonEventIncludesEntityType() throws Throwable {
-        final List<SelectionEvent> selectionEvents = new ArrayList<>();
-        final TextClassifier classifier = new TextClassifier() {
-            @Override
-            public void onSelectionEvent(SelectionEvent event) {
-                selectionEvents.add(event);
-            }
-
-            @Override
-            public TextSelection suggestSelection(TextSelection.Request request) {
-                return new TextSelection.Builder(request.getStartIndex(), request.getEndIndex())
-                        .setEntityType(TextClassifier.TYPE_PHONE, 1)
-                        .build();
-            }
-        };
+        final TestableTextClassifier classifier = new TestableTextClassifier();
         final TextView textView = mActivity.findViewById(R.id.textview);
         mActivityRule.runOnUiThread(() -> textView.setTextClassifier(classifier));
         mInstrumentation.waitForIdleSync();
+
         final String text = "My number is 987654321";
 
         onView(withId(R.id.textview)).perform(replaceText(text));
@@ -1053,6 +1041,7 @@
         long waitTime = 0;
         SelectionEvent lastEvent;
         do {
+            final List<SelectionEvent> selectionEvents = classifier.getSelectionEvents();
             lastEvent = selectionEvents.get(selectionEvents.size() - 1);
             if (lastEvent.getEventType() == SelectionEvent.ACTION_ABANDON) {
                 break;
@@ -1061,6 +1050,29 @@
             waitTime += pollInterval;
         } while (waitTime < abandonDelay * 10);
         assertEquals(SelectionEvent.ACTION_ABANDON, lastEvent.getEventType());
+    }
+
+    @Test
+    public void testSelectionMetricsLogger_overtypeEventIncludesEntityType() throws Throwable {
+        final TestableTextClassifier classifier = new TestableTextClassifier();
+        final TextView textView = mActivity.findViewById(R.id.textview);
+        mActivityRule.runOnUiThread(() -> textView.setTextClassifier(classifier));
+        mInstrumentation.waitForIdleSync();
+
+        final String text = "My number is 987654321";
+
+        // Long press to trigger selection
+        onView(withId(R.id.textview)).perform(replaceText(text));
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('9')));
+        sleepForFloatingToolbarPopup();
+
+        // Type over the selection
+        onView(withId(R.id.textview)).perform(pressKey(KeyEvent.KEYCODE_A));
+        mInstrumentation.waitForIdleSync();
+
+        final List<SelectionEvent> selectionEvents = classifier.getSelectionEvents();
+        final SelectionEvent lastEvent = selectionEvents.get(selectionEvents.size() - 1);
+        assertEquals(SelectionEvent.ACTION_OVERTYPE, lastEvent.getEventType());
         assertEquals(TextClassifier.TYPE_PHONE, lastEvent.getEntityType());
     }
 
@@ -1115,4 +1127,24 @@
     private enum TextStyle {
         PLAIN, STYLED
     }
+
+    private final class TestableTextClassifier implements TextClassifier {
+        final List<SelectionEvent> mSelectionEvents = new ArrayList<>();
+
+        @Override
+        public void onSelectionEvent(SelectionEvent event) {
+            mSelectionEvents.add(event);
+        }
+
+        @Override
+        public TextSelection suggestSelection(TextSelection.Request request) {
+            return new TextSelection.Builder(request.getStartIndex(), request.getEndIndex())
+                    .setEntityType(TextClassifier.TYPE_PHONE, 1)
+                    .build();
+        }
+
+        List<SelectionEvent> getSelectionEvents() {
+            return mSelectionEvents;
+        }
+    }
 }
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index 9863e38..66d84aa 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -54,7 +54,6 @@
 
 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;
 
@@ -76,7 +75,6 @@
 @RunWith(AndroidJUnit4.class)
 @MediumTest
 @Presubmit
-@FlakyTest(bugId = 143153552)
 public class ActivityThreadClientTest {
 
     @Test
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index f1941fc..38a9f46 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -130,7 +130,6 @@
         <permission name="android.permission.APPROVE_INCIDENT_REPORTS"/>
         <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
         <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
-        <permission name="android.permission.PACKAGE_USAGE_STATS" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.phone">
diff --git a/graphics/java/android/graphics/RuntimeShader.java b/graphics/java/android/graphics/RuntimeShader.java
index 613ce90..5a3f2a9 100644
--- a/graphics/java/android/graphics/RuntimeShader.java
+++ b/graphics/java/android/graphics/RuntimeShader.java
@@ -34,6 +34,7 @@
     }
 
     private byte[] mUniforms;
+    private boolean mIsOpaque;
 
     /**
      * Current native shader factory instance.
@@ -56,7 +57,8 @@
             ColorSpace colorSpace) {
         super(colorSpace);
         mUniforms = uniforms;
-        mNativeInstanceRuntimeShaderFactory = nativeCreateShaderFactory(sksl, isOpaque);
+        mIsOpaque = isOpaque;
+        mNativeInstanceRuntimeShaderFactory = nativeCreateShaderFactory(sksl);
         NoImagePreloadHolder.sRegistry.registerNativeAllocation(this,
                 mNativeInstanceRuntimeShaderFactory);
     }
@@ -75,13 +77,13 @@
     @Override
     long createNativeInstance(long nativeMatrix) {
         return nativeCreate(mNativeInstanceRuntimeShaderFactory, nativeMatrix, mUniforms,
-                colorSpace().getNativeInstance());
+                colorSpace().getNativeInstance(), mIsOpaque);
     }
 
     private static native long nativeCreate(long shaderFactory, long matrix, byte[] inputs,
-            long colorSpaceHandle);
+            long colorSpaceHandle, boolean isOpaque);
 
-    private static native long nativeCreateShaderFactory(String sksl, boolean isOpaque);
+    private static native long nativeCreateShaderFactory(String sksl);
 
     private static native long nativeGetFinalizer();
 }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
index c6515ef..feb6101 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
@@ -176,7 +176,7 @@
                 KeyStore keyStore, IBinder operationToken) {
             KeyStoreCryptoOperationStreamer streamer = new KeyStoreCryptoOperationChunkedStreamer(
                     new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
-                            keyStore, operationToken));
+                            keyStore, operationToken), 0);
             if (isEncrypting()) {
                 return streamer;
             } else {
@@ -191,7 +191,7 @@
         protected final KeyStoreCryptoOperationStreamer createAdditionalAuthenticationDataStreamer(
                 KeyStore keyStore, IBinder operationToken) {
             return new KeyStoreCryptoOperationChunkedStreamer(
-                    new AdditionalAuthenticationDataStream(keyStore, operationToken));
+                    new AdditionalAuthenticationDataStream(keyStore, operationToken), 0);
         }
 
         @Override
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
index 5bcb34a..ccc3153 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
@@ -299,7 +299,7 @@
             KeyStore keyStore, IBinder operationToken) {
         return new KeyStoreCryptoOperationChunkedStreamer(
                 new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
-                        keyStore, operationToken));
+                        keyStore, operationToken), 0);
     }
 
     /**
diff --git a/keystore/java/android/security/keystore/ArrayUtils.java b/keystore/java/android/security/keystore/ArrayUtils.java
index 26172d2..f519c7c 100644
--- a/keystore/java/android/security/keystore/ArrayUtils.java
+++ b/keystore/java/android/security/keystore/ArrayUtils.java
@@ -55,6 +55,34 @@
         }
     }
 
+    /**
+     * Copies a subset of the source array to the destination array.
+     * Length will be limited to the bounds of source and destination arrays.
+     * The length actually copied is returned, which will be <= length argument.
+     * @param src is the source array
+     * @param srcOffset is the offset in the source array.
+     * @param dst is the destination array.
+     * @param dstOffset is the offset in the destination array.
+     * @param length is the length to be copied from source to destination array.
+     * @return The length actually copied from source array.
+     */
+    public static int copy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int length) {
+        if (dst == null || src == null) {
+            return 0;
+        }
+        if (length > dst.length - dstOffset) {
+            length = dst.length - dstOffset;
+        }
+        if (length > src.length - srcOffset) {
+            length = src.length - srcOffset;
+        }
+        if (length <= 0) {
+            return 0;
+        }
+        System.arraycopy(src, srcOffset, dst, dstOffset, length);
+        return length;
+    }
+
     public static byte[] subarray(byte[] arr, int offset, int len) {
         if (len == 0) {
             return EmptyArray.BYTE;
diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
index 75bea26..2c0f40d 100644
--- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
+++ b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
@@ -24,19 +24,20 @@
 
 import libcore.util.EmptyArray;
 
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.security.ProviderException;
-
 /**
  * Helper for streaming a crypto operation's input and output via {@link KeyStore} service's
  * {@code update} and {@code finish} operations.
  *
- * <p>The helper abstracts away to issues that need to be solved in most code that uses KeyStore's
+ * <p>The helper abstracts away issues that need to be solved in most code that uses KeyStore's
  * update and finish operations. Firstly, KeyStore's update operation can consume only a limited
  * amount of data in one go because the operations are marshalled via Binder. Secondly, the update
  * operation may consume less data than provided, in which case the caller has to buffer the
- * remainder for next time. The helper exposes {@link #update(byte[], int, int) update} and
+ * remainder for next time. Thirdly, when the input is smaller than a threshold, skipping update
+ * and passing input data directly to final improves performance. This threshold is configurable;
+ * using a threshold <= 1 causes the helper act eagerly, which may be required for some types of
+ * operations (e.g. ciphers).
+ *
+ * <p>The helper exposes {@link #update(byte[], int, int) update} and
  * {@link #doFinal(byte[], int, int, byte[], byte[]) doFinal} operations which can be used to
  * conveniently implement various JCA crypto primitives.
  *
@@ -67,240 +68,122 @@
 
     // Binder buffer is about 1MB, but it's shared between all active transactions of the process.
     // Thus, it's safer to use a much smaller upper bound.
-    private static final int DEFAULT_MAX_CHUNK_SIZE = 64 * 1024;
+    private static final int DEFAULT_CHUNK_SIZE_MAX = 64 * 1024;
+    // The chunk buffer will be sent to update until its size under this threshold.
+    // This threshold should be <= the max input allowed for finish.
+    // Setting this threshold <= 1 will effectivley disable buffering between updates.
+    private static final int DEFAULT_CHUNK_SIZE_THRESHOLD = 2 * 1024;
 
     private final Stream mKeyStoreStream;
-    private final int mMaxChunkSize;
-
-    private byte[] mBuffered = EmptyArray.BYTE;
-    private int mBufferedOffset;
-    private int mBufferedLength;
+    private final int mChunkSizeMax;
+    private final int mChunkSizeThreshold;
+    private final byte[] mChunk;
+    private int mChunkLength = 0;
     private long mConsumedInputSizeBytes;
     private long mProducedOutputSizeBytes;
 
-    public KeyStoreCryptoOperationChunkedStreamer(Stream operation) {
-        this(operation, DEFAULT_MAX_CHUNK_SIZE);
+    KeyStoreCryptoOperationChunkedStreamer(Stream operation) {
+        this(operation, DEFAULT_CHUNK_SIZE_THRESHOLD, DEFAULT_CHUNK_SIZE_MAX);
     }
 
-    public KeyStoreCryptoOperationChunkedStreamer(Stream operation, int maxChunkSize) {
+    KeyStoreCryptoOperationChunkedStreamer(Stream operation, int chunkSizeThreshold) {
+        this(operation, chunkSizeThreshold, DEFAULT_CHUNK_SIZE_MAX);
+    }
+
+    KeyStoreCryptoOperationChunkedStreamer(Stream operation, int chunkSizeThreshold,
+            int chunkSizeMax) {
         mKeyStoreStream = operation;
-        mMaxChunkSize = maxChunkSize;
+        mChunkSizeMax = chunkSizeMax;
+        if (chunkSizeThreshold <= 0) {
+            mChunkSizeThreshold = 1;
+        } else if (chunkSizeThreshold > chunkSizeMax) {
+            mChunkSizeThreshold = chunkSizeMax;
+        } else {
+            mChunkSizeThreshold = chunkSizeThreshold;
+        }
+        mChunk = new byte[mChunkSizeMax];
     }
 
-    @Override
     public byte[] update(byte[] input, int inputOffset, int inputLength) throws KeyStoreException {
-        if (inputLength == 0) {
+        if (inputLength == 0 || input == null) {
             // No input provided
             return EmptyArray.BYTE;
         }
+        if (inputLength < 0 || inputOffset < 0 || (inputOffset + inputLength) > input.length) {
+            throw new KeyStoreException(KeymasterDefs.KM_ERROR_UNKNOWN_ERROR,
+                "Input offset and length out of bounds of input array");
+        }
 
-        ByteArrayOutputStream bufferedOutput = null;
+        byte[] output = EmptyArray.BYTE;
 
-        while (inputLength > 0) {
-            byte[] chunk;
-            int inputBytesInChunk;
-            if ((mBufferedLength + inputLength) > mMaxChunkSize) {
-                // Too much input for one chunk -- extract one max-sized chunk and feed it into the
-                // update operation.
-                inputBytesInChunk = mMaxChunkSize - mBufferedLength;
-                chunk = ArrayUtils.concat(mBuffered, mBufferedOffset, mBufferedLength,
-                        input, inputOffset, inputBytesInChunk);
-            } else {
-                // All of available input fits into one chunk.
-                if ((mBufferedLength == 0) && (inputOffset == 0)
-                        && (inputLength == input.length)) {
-                    // Nothing buffered and all of input array needs to be fed into the update
-                    // operation.
-                    chunk = input;
-                    inputBytesInChunk = input.length;
-                } else {
-                    // Need to combine buffered data with input data into one array.
-                    inputBytesInChunk = inputLength;
-                    chunk = ArrayUtils.concat(mBuffered, mBufferedOffset, mBufferedLength,
-                            input, inputOffset, inputBytesInChunk);
+        while (inputLength > 0 || mChunkLength >= mChunkSizeThreshold) {
+            int inputConsumed = ArrayUtils.copy(input, inputOffset, mChunk, mChunkLength,
+                    inputLength);
+            inputLength -= inputConsumed;
+            inputOffset += inputConsumed;
+            mChunkLength += inputConsumed;
+            mConsumedInputSizeBytes += inputConsumed;
+
+            if (mChunkLength > mChunkSizeMax) {
+                throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH,
+                    "Chunk size exceeded max chunk size. Max: " + mChunkSizeMax
+                    + " Actual: " + mChunkLength);
+            }
+
+            if (mChunkLength >= mChunkSizeThreshold) {
+                OperationResult opResult = mKeyStoreStream.update(
+                        ArrayUtils.subarray(mChunk, 0, mChunkLength));
+
+                if (opResult == null) {
+                    throw new KeyStoreConnectException();
+                } else if (opResult.resultCode != KeyStore.NO_ERROR) {
+                    throw KeyStore.getKeyStoreException(opResult.resultCode);
                 }
-            }
-            // Update input array references to reflect that some of its bytes are now in mBuffered.
-            inputOffset += inputBytesInChunk;
-            inputLength -= inputBytesInChunk;
-            mConsumedInputSizeBytes += inputBytesInChunk;
-
-            OperationResult opResult = mKeyStoreStream.update(chunk);
-            if (opResult == null) {
-                throw new KeyStoreConnectException();
-            } else if (opResult.resultCode != KeyStore.NO_ERROR) {
-                throw KeyStore.getKeyStoreException(opResult.resultCode);
-            }
-
-            if (opResult.inputConsumed == chunk.length) {
-                // The whole chunk was consumed
-                mBuffered = EmptyArray.BYTE;
-                mBufferedOffset = 0;
-                mBufferedLength = 0;
-            } else if (opResult.inputConsumed <= 0) {
-                // Nothing was consumed. More input needed.
-                if (inputLength > 0) {
-                    // More input is available, but it wasn't included into the previous chunk
-                    // because the chunk reached its maximum permitted size.
-                    // Shouldn't have happened.
+                if (opResult.inputConsumed <= 0) {
+                    throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH,
+                        "Keystore consumed 0 of " + mChunkLength + " bytes provided.");
+                } else if (opResult.inputConsumed > mChunkLength) {
                     throw new KeyStoreException(KeymasterDefs.KM_ERROR_UNKNOWN_ERROR,
-                            "Keystore consumed nothing from max-sized chunk: " + chunk.length
-                                    + " bytes");
+                        "Keystore consumed more input than provided. Provided: "
+                            + mChunkLength + ", consumed: " + opResult.inputConsumed);
                 }
-                mBuffered = chunk;
-                mBufferedOffset = 0;
-                mBufferedLength = chunk.length;
-            } else if (opResult.inputConsumed < chunk.length) {
-                // The chunk was consumed only partially -- buffer the rest of the chunk
-                mBuffered = chunk;
-                mBufferedOffset = opResult.inputConsumed;
-                mBufferedLength = chunk.length - opResult.inputConsumed;
-            } else {
-                throw new KeyStoreException(KeymasterDefs.KM_ERROR_UNKNOWN_ERROR,
-                        "Keystore consumed more input than provided. Provided: " + chunk.length
-                                + ", consumed: " + opResult.inputConsumed);
-            }
+                mChunkLength -= opResult.inputConsumed;
 
-            if ((opResult.output != null) && (opResult.output.length > 0)) {
-                if (inputLength + mBufferedLength > 0) {
-                    // More output might be produced in this loop -- buffer the current output
-                    if (bufferedOutput == null) {
-                        bufferedOutput = new ByteArrayOutputStream();
-                    }
-                    try {
-                        bufferedOutput.write(opResult.output);
-                    } catch (IOException e) {
-                        throw new ProviderException("Failed to buffer output", e);
-                    }
-                } else {
-                    // No more output will be produced in this loop
-                    byte[] result;
-                    if (bufferedOutput == null) {
-                        // No previously buffered output
-                        result = opResult.output;
-                    } else {
-                        // There was some previously buffered output
-                        try {
-                            bufferedOutput.write(opResult.output);
-                        } catch (IOException e) {
-                            throw new ProviderException("Failed to buffer output", e);
-                        }
-                        result = bufferedOutput.toByteArray();
-                    }
-                    mProducedOutputSizeBytes += result.length;
-                    return result;
+                if (mChunkLength > 0) {
+                    // Partialy consumed, shift chunk contents
+                    ArrayUtils.copy(mChunk, opResult.inputConsumed, mChunk, 0, mChunkLength);
+                }
+
+                if ((opResult.output != null) && (opResult.output.length > 0)) {
+                    // Output was produced
+                    mProducedOutputSizeBytes += opResult.output.length;
+                    output = ArrayUtils.concat(output, opResult.output);
                 }
             }
         }
-
-        byte[] result;
-        if (bufferedOutput == null) {
-            // No output produced
-            result = EmptyArray.BYTE;
-        } else {
-            result = bufferedOutput.toByteArray();
-        }
-        mProducedOutputSizeBytes += result.length;
-        return result;
+        return output;
     }
 
-    @Override
     public byte[] doFinal(byte[] input, int inputOffset, int inputLength,
             byte[] signature, byte[] additionalEntropy) throws KeyStoreException {
-        if (inputLength == 0) {
-            // No input provided -- simplify the rest of the code
-            input = EmptyArray.BYTE;
-            inputOffset = 0;
-        }
-
-        // Flush all buffered input and provided input into keystore/keymaster.
         byte[] output = update(input, inputOffset, inputLength);
-        output = ArrayUtils.concat(output, flush());
+        byte[] finalChunk = ArrayUtils.subarray(mChunk, 0, mChunkLength);
+        OperationResult opResult = mKeyStoreStream.finish(finalChunk, signature, additionalEntropy);
 
-        OperationResult opResult = mKeyStoreStream.finish(EmptyArray.BYTE, signature,
-                                                          additionalEntropy);
         if (opResult == null) {
             throw new KeyStoreConnectException();
         } else if (opResult.resultCode != KeyStore.NO_ERROR) {
             throw KeyStore.getKeyStoreException(opResult.resultCode);
         }
-        mProducedOutputSizeBytes += opResult.output.length;
+        // If no error, assume all input consumed
+        mConsumedInputSizeBytes += finalChunk.length;
 
-        return ArrayUtils.concat(output, opResult.output);
-    }
-
-    public byte[] flush() throws KeyStoreException {
-        if (mBufferedLength <= 0) {
-            return EmptyArray.BYTE;
+        if ((opResult.output != null) && (opResult.output.length > 0)) {
+            mProducedOutputSizeBytes += opResult.output.length;
+            output = ArrayUtils.concat(output, opResult.output);
         }
 
-        // Keep invoking the update operation with remaining buffered data until either all of the
-        // buffered data is consumed or until update fails to consume anything.
-        ByteArrayOutputStream bufferedOutput = null;
-        while (mBufferedLength > 0) {
-            byte[] chunk = ArrayUtils.subarray(mBuffered, mBufferedOffset, mBufferedLength);
-            OperationResult opResult = mKeyStoreStream.update(chunk);
-            if (opResult == null) {
-                throw new KeyStoreConnectException();
-            } else if (opResult.resultCode != KeyStore.NO_ERROR) {
-                throw KeyStore.getKeyStoreException(opResult.resultCode);
-            }
-
-            if (opResult.inputConsumed <= 0) {
-                // Nothing was consumed. Break out of the loop to avoid an infinite loop.
-                break;
-            }
-
-            if (opResult.inputConsumed >= chunk.length) {
-                // All of the input was consumed
-                mBuffered = EmptyArray.BYTE;
-                mBufferedOffset = 0;
-                mBufferedLength = 0;
-            } else {
-                // Some of the input was not consumed
-                mBuffered = chunk;
-                mBufferedOffset = opResult.inputConsumed;
-                mBufferedLength = chunk.length - opResult.inputConsumed;
-            }
-
-            if (opResult.inputConsumed > chunk.length) {
-                throw new KeyStoreException(KeymasterDefs.KM_ERROR_UNKNOWN_ERROR,
-                        "Keystore consumed more input than provided. Provided: "
-                                + chunk.length + ", consumed: " + opResult.inputConsumed);
-            }
-
-            if ((opResult.output != null) && (opResult.output.length > 0)) {
-                // Some output was produced by this update operation
-                if (bufferedOutput == null) {
-                    // No output buffered yet.
-                    if (mBufferedLength == 0) {
-                        // No more output will be produced by this flush operation
-                        mProducedOutputSizeBytes += opResult.output.length;
-                        return opResult.output;
-                    } else {
-                        // More output might be produced by this flush operation -- buffer output.
-                        bufferedOutput = new ByteArrayOutputStream();
-                    }
-                }
-                // Buffer the output from this update operation
-                try {
-                    bufferedOutput.write(opResult.output);
-                } catch (IOException e) {
-                    throw new ProviderException("Failed to buffer output", e);
-                }
-            }
-        }
-
-        if (mBufferedLength > 0) {
-            throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH,
-                    "Keystore failed to consume last "
-                            + ((mBufferedLength != 1) ? (mBufferedLength + " bytes") : "byte")
-                            + " of input");
-        }
-
-        byte[] result = (bufferedOutput != null) ? bufferedOutput.toByteArray() : EmptyArray.BYTE;
-        mProducedOutputSizeBytes += result.length;
-        return result;
+        return output;
     }
 
     @Override
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java
index d79849c..4e0fd4a 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java
@@ -252,6 +252,11 @@
     }
 
     @Override
+    public boolean isPluggedIn() {
+        return true;
+    }
+
+    @Override
     public boolean isPowerSave() {
         // Power save is not valid for the car, so always return false.
         return false;
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
index 8a2948b..3b3933b 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
@@ -16,9 +16,6 @@
 
 package com.android.dynsystem;
 
-import static android.os.image.DynamicSystemClient.KEY_SYSTEM_SIZE;
-import static android.os.image.DynamicSystemClient.KEY_USERDATA_SIZE;
-
 import android.app.Activity;
 import android.app.KeyguardManager;
 import android.content.Context;
@@ -88,12 +85,8 @@
     private void startInstallationService() {
         // retrieve data from calling intent
         Intent callingIntent = getIntent();
-
         Uri url = callingIntent.getData();
-        long systemSize = callingIntent.getLongExtra(KEY_SYSTEM_SIZE, 0);
-        long userdataSize = callingIntent.getLongExtra(KEY_USERDATA_SIZE, 0);
-        boolean enableWhenCompleted = callingIntent.getBooleanExtra(
-                DynamicSystemInstallationService.KEY_ENABLE_WHEN_COMPLETED, false);
+        Bundle extras = callingIntent.getExtras();
 
         sVerifiedUrl = url.toString();
 
@@ -101,10 +94,7 @@
         Intent intent = new Intent(this, DynamicSystemInstallationService.class);
         intent.setData(url);
         intent.setAction(DynamicSystemClient.ACTION_START_INSTALL);
-        intent.putExtra(KEY_SYSTEM_SIZE, systemSize);
-        intent.putExtra(KEY_USERDATA_SIZE, userdataSize);
-        intent.putExtra(
-                DynamicSystemInstallationService.KEY_ENABLE_WHEN_COMPLETED, enableWhenCompleted);
+        intent.putExtras(extras);
 
         Log.d(TAG, "Starting Installation Service");
         startServiceAsUser(intent, UserHandle.SYSTEM);
diff --git a/packages/InputDevices/res/values-el/strings.xml b/packages/InputDevices/res/values-el/strings.xml
index 05de3b7..b9d65c5 100644
--- a/packages/InputDevices/res/values-el/strings.xml
+++ b/packages/InputDevices/res/values-el/strings.xml
@@ -8,7 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Αγγλικά (ΗΠΑ), τύπου International"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Αγγλικά (ΗΠΑ), τύπου Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Αγγλικά (ΗΠΑ), τύπου Dvorak"</string>
-    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Αγγλικά (ΗΠΑ), στυλ Workman"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Αγγλικά (ΗΠΑ), στιλ Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Γερμανικά"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Γαλλικά"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Γαλλικά (Καναδά)"</string>
diff --git a/packages/SettingsLib/res/values-ar/arrays.xml b/packages/SettingsLib/res/values-ar/arrays.xml
index 7fc65a3..b4f5253 100644
--- a/packages/SettingsLib/res/values-ar/arrays.xml
+++ b/packages/SettingsLib/res/values-ar/arrays.xml
@@ -170,7 +170,7 @@
   <string-array name="select_logpersist_titles">
     <item msgid="704720725704372366">"إيقاف"</item>
     <item msgid="6014837961827347618">"الكل"</item>
-    <item msgid="7387060437894578132">"الكل دون اللاسلكي"</item>
+    <item msgid="7387060437894578132">"الكل بدون اللاسلكي"</item>
     <item msgid="7300881231043255746">"‏kernel فقط"</item>
   </string-array>
   <string-array name="select_logpersist_summaries">
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index d4e1b63..43d2ece 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -68,14 +68,14 @@
     <string name="bluetooth_connecting" msgid="5871702668260192755">"جارٍ الاتصال…"</string>
     <string name="bluetooth_connected" msgid="8065345572198502293">"الجهاز متصل<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
     <string name="bluetooth_pairing" msgid="4269046942588193600">"جارٍ الاقتران..."</string>
-    <string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"الجهاز متصل (من دون هاتف)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
-    <string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"الجهاز متصل (من دون وسائط)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
-    <string name="bluetooth_connected_no_map" msgid="3381860077002724689">"الجهاز متصل (من دون وصول إلى الرسائل)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
-    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="2893204819854215433">"الجهاز متصل (من دون هاتف أو وسائط)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"الجهاز متصل (بدون هاتف)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"الجهاز متصل (بدون وسائط)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_map" msgid="3381860077002724689">"الجهاز متصل (بدون وصول إلى الرسائل)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="2893204819854215433">"الجهاز متصل (بدون هاتف أو وسائط)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
     <string name="bluetooth_connected_battery_level" msgid="5410325759372259950">"الجهاز متصل، ومستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
-    <string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"الجهاز متصل (من دون هاتف)، ومستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
-    <string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"الجهاز متصل (من دون وسائط)، ومستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
-    <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"الجهاز متّصل (من دون هاتف أو وسائط)، ومستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"الجهاز متصل (بدون هاتف)، ومستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"الجهاز متصل (بدون وسائط)، ومستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"الجهاز متّصل (بدون هاتف أو وسائط)، ومستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
     <string name="bluetooth_active_battery_level" msgid="3450745316700494425">"نشط، ومستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
     <string name="bluetooth_active_battery_level_untethered" msgid="2706188607604205362">"مفعّلة، مستوى البطارية: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>، المعدّل: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string>
     <string name="bluetooth_battery_level" msgid="2893696778200201555">"مستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 07d5ccb..3f99d10 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -227,8 +227,7 @@
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Konexioa partekatzeko hardwarearen azelerazioa"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Erakutsi Bluetooth gailuak izenik gabe"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desgaitu bolumen absolutua"</string>
-    <!-- no translation found for bluetooth_enable_gabeldorsche (9131730396242883416) -->
-    <skip />
+    <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gaitu Gabeldorsche"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP bertsioa"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Hautatu Bluetooth AVRCP bertsioa"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="952001408455456494">"Bluetooth bidezko audioaren kodeka"</string>
@@ -277,8 +276,7 @@
     <string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"Egiaztatu ADB/ADT bidez instalatutako aplikazioak portaera kaltegarriak atzemateko"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"Bluetooth gailuak izenik gabe (MAC helbideak soilik) erakutsiko dira"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"Bluetooth bidezko bolumen absolutuaren eginbidea desgaitu egiten du urruneko gailuetan arazoak hautematen badira; esaterako, bolumena ozenegia bada edo ezin bada kontrolatu"</string>
-    <!-- no translation found for bluetooth_enable_gabeldorsche_summary (8472344901097607030) -->
-    <skip />
+    <string name="bluetooth_enable_gabeldorsche_summary" msgid="8472344901097607030">"Bluetooth Gabeldorsche eginbide sorta gaitzen du."</string>
     <string name="enable_terminal_title" msgid="3834790541986303654">"Tokiko terminala"</string>
     <string name="enable_terminal_summary" msgid="2481074834856064500">"Gaitu tokiko shell-sarbidea duen terminal-aplikazioa"</string>
     <string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP egiaztapena"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 154f386..f9ac3a5 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -227,8 +227,7 @@
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"हार्डवेयर से तेज़ी लाने के लिए टेदर करें"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"बिना नाम वाले ब्लूटूथ डिवाइस दिखाएं"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ब्लूटूथ से आवाज़ के नियंत्रण की सुविधा रोकें"</string>
-    <!-- no translation found for bluetooth_enable_gabeldorsche (9131730396242883416) -->
-    <skip />
+    <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche चालू करें"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ब्लूटूथ एवीआरसीपी वर्शन"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ब्लूटूथ AVRCP वर्शन चुनें"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="952001408455456494">"ब्लूटूथ ऑडियो कोडेक"</string>
@@ -277,8 +276,7 @@
     <string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"नुकसानदेह व्यवहार के लिए ADB/ADT से इंस्टॉल किए गए ऐप्लिकेशन जाँचें."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"बिना नाम वाले ब्लूटूथ डिवाइस (केवल MAC पते वाले) दिखाए जाएंगे"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"दूर के डिवाइस पर आवाज़ बहुत बढ़ जाने या उससे नियंत्रण हटने जैसी समस्याएं होने पर, यह ब्लूटूथ के ज़रिए आवाज़ के नियंत्रण की सुविधा रोक देता है."</string>
-    <!-- no translation found for bluetooth_enable_gabeldorsche_summary (8472344901097607030) -->
-    <skip />
+    <string name="bluetooth_enable_gabeldorsche_summary" msgid="8472344901097607030">"Bluetooth Gabeldorsche सुविधा का स्टैक चालू करें."</string>
     <string name="enable_terminal_title" msgid="3834790541986303654">"स्थानीय टर्मिनल"</string>
     <string name="enable_terminal_summary" msgid="2481074834856064500">"लोकल शेल तक पहुंचने की सुविधा देने वाले टर्मिनल ऐप को चालू करें"</string>
     <string name="hdcp_checking_title" msgid="3155692785074095986">"एचडीसीपी जाँच"</string>
diff --git a/packages/SettingsLib/res/values-sl/arrays.xml b/packages/SettingsLib/res/values-sl/arrays.xml
index 4c22bda..d946316 100644
--- a/packages/SettingsLib/res/values-sl/arrays.xml
+++ b/packages/SettingsLib/res/values-sl/arrays.xml
@@ -82,8 +82,6 @@
     <item msgid="1049450003868150455">"Zvok <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
     <item msgid="2908219194098827570">"Zvok <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
     <item msgid="3825367753087348007">"LDAC"</item>
-    <item msgid="5832677994279829983">"Omogoči izbirne kodeke"</item>
-    <item msgid="9205039209798344398">"Onemogoči izbirne kodeke"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_summaries">
     <item msgid="8868109554557331312">"Uporabi sistemsko izbiro (privzeto)"</item>
@@ -92,8 +90,6 @@
     <item msgid="8627333814413492563">"Zvok <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
     <item msgid="3517061573669307965">"Zvok <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
     <item msgid="2553206901068987657">"LDAC"</item>
-    <item msgid="221347164942544028">"Omogoči izbirne kodeke"</item>
-    <item msgid="7416462860415701287">"Onemogoči izbirne kodeke"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
     <item msgid="926809261293414607">"Uporabi sistemsko izbiro (privzeto)"</item>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 90d7829..efd7c08 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -227,6 +227,7 @@
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Strojno pospeševanje za internetno povezavo prek mobilnega telefona"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži naprave Bluetooth brez imen"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Onemogočanje absolutne glasnosti"</string>
+    <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Omogoči Gabeldorsche"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Različica profila AVRCP za Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Izberite različico profila AVRCP za Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="952001408455456494">"Zvočni kodek za Bluetooth"</string>
@@ -275,6 +276,7 @@
     <string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"Preveri, ali so aplikacije, nameščene prek ADB/ADT, škodljive."</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"Prikazane bodo naprave Bluetooth brez imen (samo z naslovi MAC)"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"Onemogoči funkcijo absolutne glasnosti za Bluetooth, če pride do težav z glasnostjo z oddaljenimi napravami, kot je nesprejemljivo visoka glasnost ali pomanjkanje nadzora."</string>
+    <string name="bluetooth_enable_gabeldorsche_summary" msgid="8472344901097607030">"Omogoči sklad funkcij Bluetooth Gabeldorche."</string>
     <string name="enable_terminal_title" msgid="3834790541986303654">"Lokalni terminal"</string>
     <string name="enable_terminal_summary" msgid="2481074834856064500">"Omogočanje terminalske aplikacije za dostop do lokalne lupine"</string>
     <string name="hdcp_checking_title" msgid="3155692785074095986">"Preverjanje HDCP"</string>
@@ -379,7 +381,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalija (rdeča – zelena)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalija (modra – rumena)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Popravljanje barv"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="5190814747212060815">"To je preskusna funkcija in lahko vpliva na učinkovitost delovanja."</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="9137381746633858694">"Popravljanje barv osebam z barvno slepoto pomaga, da vidijo bolj prave barve"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Preglasila nastavitev: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Še približno <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 9b4a6d6..7b589370 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -132,6 +132,20 @@
         <item>avrcp16</item>
     </string-array>
 
+    <!-- Titles for Bluetooth MAP Versions -->
+    <string-array name="bluetooth_map_versions">
+        <item>MAP 1.2 (Default)</item>
+        <item>MAP 1.3</item>
+        <item>MAP 1.4</item>
+    </string-array>
+
+    <!-- Values for Bluetooth MAP Versions -->
+    <string-array name="bluetooth_map_version_values">
+        <item>map12</item>
+        <item>map13</item>
+        <item>map14</item>
+    </string-array>
+
     <!-- Titles for Bluetooth Audio Codec selection preference. [CHAR LIMIT=50] -->
     <string-array name="bluetooth_a2dp_codec_titles">
         <item>Use System Selection (Default)</item>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index f40105d..a7df6db 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -606,6 +606,11 @@
     <!-- UI debug setting: Select Bluetooth AVRCP Version -->
     <string name="bluetooth_select_avrcp_version_dialog_title">Select Bluetooth AVRCP Version</string>
 
+    <!-- UI debug setting: Select Bluetooth MAP Version [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_select_map_version_string">Bluetooth MAP Version</string>
+    <!-- UI debug setting: Select Bluetooth MAP Version [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_select_map_version_dialog_title">Select Bluetooth MAP Version</string>
+
     <!-- UI debug setting: Trigger Bluetooth Audio Codec Selection -->
     <string name="bluetooth_select_a2dp_codec_type">Bluetooth Audio Codec</string>
     <!-- UI debug setting: Trigger Bluetooth Audio Codec Selection -->
@@ -699,7 +704,7 @@
     <!-- Summary of checkbox for disabling Bluetooth absolute volume -->
     <string name="bluetooth_disable_absolute_volume_summary">Disables the Bluetooth absolute volume feature in case of volume issues with remote devices such as unacceptably loud volume or lack of control.</string>
     <!-- Summary of checkbox for enabling Bluetooth Gabeldorche features [CHAR LIMIT=none] -->
-    <string name="bluetooth_enable_gabeldorsche_summary">Enables the Bluetooth Gabeldorche feature stack.</string>
+    <string name="bluetooth_enable_gabeldorsche_summary">Enables the Bluetooth Gabeldorsche feature stack.</string>
 
     <!-- Title of checkbox setting that enables the terminal app. [CHAR LIMIT=32] -->
     <string name="enable_terminal_title">Local terminal</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
index e19ac81..6d7e86f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.PowerManager;
+import android.os.UserHandle;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
 import android.text.TextUtils;
@@ -186,7 +187,8 @@
     }
 
     private static void setBatterySaverConfirmationAcknowledged(Context context) {
-        Secure.putInt(context.getContentResolver(), Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1);
+        Secure.putIntForUser(context.getContentResolver(), Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1,
+                UserHandle.USER_CURRENT);
     }
 
     /**
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
index 52ec1f0..0a2dd6c 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/FalsingManager.java
@@ -30,7 +30,7 @@
  */
 @ProvidesInterface(version = FalsingManager.VERSION)
 public interface FalsingManager {
-    int VERSION = 2;
+    int VERSION = 3;
 
     void onSucccessfulUnlock();
 
@@ -48,7 +48,7 @@
 
     void setNotificationExpanded();
 
-    boolean isClassiferEnabled();
+    boolean isClassifierEnabled();
 
     void onQsDown();
 
diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml
index efe4088..393da27 100644
--- a/packages/SystemUI/res-keyguard/values-ar/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml
@@ -74,7 +74,7 @@
     <string name="kg_pattern_instructions" msgid="5376036737065051736">"ارسم نقشك"</string>
     <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"‏أدخل رقم التعريف الشخصي لشريحة SIM."</string>
     <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"‏أدخل رقم التعريف الشخصي لشريحة SIM التابعة للمشغّل \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
-    <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"‏<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> يجب إيقاف eSIM لاستخدام الجهاز دون خدمة جوّال."</string>
+    <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"‏<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> يجب إيقاف eSIM لاستخدام الجهاز بدون خدمة الأجهزة الجوّالة."</string>
     <string name="kg_pin_instructions" msgid="822353548385014361">"أدخل رقم التعريف الشخصي"</string>
     <string name="kg_password_instructions" msgid="324455062831719903">"أدخل كلمة المرور"</string>
     <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"‏شريحة SIM غير مفعّلة الآن. أدخل رمز PUK للمتابعة. اتصل بمشغل شبكة الجوّال للاطلاع على التفاصيل."</string>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 08be42a..ea7b9bb 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Skakel Batterybespaarder af"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sal toegang hê tot al die inligting wat op jou skerm sigbaar is of wat op jou toestel gespeel word terwyl dit opneem of uitsaai. Dit sluit in inligting soos wagwoorde, betalingbesonderhede, foto\'s, boodskappe en oudio wat jy speel."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Die diens wat hierdie funksie verskaf, sal toegang hê tot al die inligting wat op jou skerm sigbaar is of wat op jou toestel gespeel word terwyl dit opneem of uitsaai. Dit sluit in inligting soos wagwoorde, betalingbesonderhede, foto\'s, boodskappe en oudio wat jy speel."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Begin opneem of uitsaai?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Begin opneem of uitsaai met <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Moenie weer wys nie"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Vee alles uit"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 18a4a7a..9412f0f 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"ባትሪ ቆጣቢን አጥፋ"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> በእርስዎ ማያ ገጽ ላይ ያለን ወይም በእርስዎ መሣሪያ ላይ በመጫወት ላይ ያለን ሁሉንም መረጃ በቀረጻ ወይም casting ላይ እያለ መዳረሻ ይኖረዋል። ይህ እንደ የይለፍ ቃላት፣ የክፍያ ዝርዝሮች፣ ፎቶዎች፣ መልዕክቶች እና እርስዎ የሚጫውቱት ኦዲዮን የመሳሰለ መረጃን ያካትታል።"</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"ይህን ተግባር የሚያቀርበው አገልግሎት በእርስዎ ማያ ገጽ ላይ ያለን ወይም በእርስዎ መሣሪያ ላይ በመጫወት ላይ ያለን ሁሉንም መረጃ በቀረጻ ወይም casting ላይ እያለ መዳረሻ ይኖረዋል። ይህ እንደ የይለፍ ቃላት፣ የክፍያ ዝርዝሮች፣ ፎቶዎች፣ መልዕክቶች እና እርስዎ የሚጫውቱት ኦዲዮን የመሳሰለ መረጃን ያካትታል።"</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ቀረጻ ወይም cast ማድረግ ይጀምር?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"ከ<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ጋር ቀረጻ ወይም casting ይጀምር?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"ዳግመኛ አታሳይ"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"ሁሉንም አጽዳ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 07be692..f675265 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -111,7 +111,7 @@
     <string name="accessibility_voice_assist_button" msgid="6497706615649754510">"المساعد الصوتي"</string>
     <string name="accessibility_unlock_button" msgid="122785427241471085">"إلغاء القفل"</string>
     <string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"في انتظار بصمة الإصبع"</string>
-    <string name="accessibility_unlock_without_fingerprint" msgid="1811563723195375298">"إلغاء القفل دون استخدام بصمة إصبعك"</string>
+    <string name="accessibility_unlock_without_fingerprint" msgid="1811563723195375298">"فتح القفل بدون استخدام بصمة إصبعك"</string>
     <string name="accessibility_scanning_face" msgid="3093828357921541387">"مسح الوجه"</string>
     <string name="accessibility_send_smart_reply" msgid="8885032190442015141">"إرسال"</string>
     <string name="accessibility_manage_notification" msgid="582215815790143983">"إدارة الإشعارات"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 14f5e7f..2b94d67 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -468,8 +468,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Isključi Uštedu baterije"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> će imati pristup svim informacijama koje se prikazuju na ekranu ili reprodukuju sa uređaja tokom snimanja ili prebacivanja. To obuhvata informacije poput lozinki, informacija o plaćanju, slika, poruka i zvuka koji puštate."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Usluga koja pruža ovu funkciju će imati pristup svim informacijama koje se prikazuju na ekranu ili reprodukuju sa uređaja tokom snimanja ili prebacivanja. To obuhvata informacije poput lozinki, informacija o plaćanju, slika, poruka i zvuka koji puštate."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Želite da počnete snimanje ili prebacivanje?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Želite da počnete snimanje ili prebacivanje pomoću aplikacije <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Ne prikazuj ponovo"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Obriši sve"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 9b7b62a..26102fb 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Изключване на режима за запазване на батерията"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ще има достъп до цялата информация, която е видима на екрана или възпроизвеждана от устройството ви по време на записване или предаване. Това включва различна информация, като например пароли, данни за плащане, снимки, съобщения и възпроизвеждано аудио."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Услугата, предоставяща тази функция, ще има достъп до цялата информация, която е видима на екрана или възпроизвеждана от устройството ви по време на записване или предаване. Това включва различна информация, като например пароли, данни за плащане, снимки, съобщения и възпроизвеждано аудио."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Да се стартира ли записване или предаване?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Да се стартира ли записване или предаване чрез <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Да не се показва отново"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Изчистване на всички"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 6e2285e..5851011 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -468,8 +468,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Isključi Uštedu baterije"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"Aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> će imati pristup svim informacijama koje se prikazuju na ekranu ili koje se reproduciraju s vašeg uređaja za vrijeme snimanja ili emitiranja. To obuhvata informacije kao što su lozinke, detalji o plaćanju, fotografije, poruke i zvuk koji reproducirate."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Usluga koja pruža ovu funkciju će imati pristup svim informacijama koje se prikazuju na ekranu ili koje se reproduciraju s vašeg uređaja za vrijeme snimanja ili emitiranja. To obuhvata informacije kao što su lozinke, detalji o plaćanju, fotografije, poruke i zvuk koji reproducirate."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Započeti snimanje ili emitiranje?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Započeti snimanje ili emitiranje s aplikacijom <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Ne prikazuj opet"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Očisti sve"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 4909e10..9fb7230 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desactiva l\'estalvi de bateria"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tindrà accés a tota la informació que es veu en pantalla o que es reprodueix al dispositiu mentre graves o emets contingut, com ara contrasenyes, detalls dels pagaments, fotos, missatges i àudio."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"El servei que ofereix aquesta funció tindrà accés a tota la informació que es veu en pantalla o que es reprodueix al dispositiu mentre graves o emets contingut, com ara contrasenyes, detalls dels pagaments, fotos, missatges i àudio."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Vols començar a gravar o emetre contingut?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Vols començar a gravar o emetre contingut amb <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"No ho tornis a mostrar"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Esborra-ho tot"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index b5b8aa3..30724f8 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -471,8 +471,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Vypnout spořič baterie"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"Aplikace <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> bude mít přístup ke všem informacím, které jsou viditelné na obrazovce nebo které jsou přehrávány ze za řízení při nahrávání nebo odesílání. Týká se to i hesel, údajů o platbě, fotek, zpráv a přehrávaných zvuků."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Služba, která poskytuje tuto funkci, bude mít přístup ke všem informacím, které jsou viditelné na obrazovce nebo které jsou přehrávány ze zařízení při nahrávání nebo odesílání. Týká se to i hesel, údajů o platbě, fotek, zpráv a přehrávaných zvuků."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Začít nahrávat nebo odesílat?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Začít nahrávat nebo odesílat s aplikací <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Tuto zprávu příště nezobrazovat"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Smazat vše"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 80c8d28..e20a276 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Deaktiver batterisparefunktion"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> får adgang til alle de oplysninger, der er synlige på din skærm, eller som afspilles på din enhed, når du optager eller caster. Dette omfatter oplysninger som f.eks. adgangskoder, betalingsoplysninger, billeder, beskeder og afspillet lyd."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Tjenesten, der tilbyder denne funktion, får adgang til alle de oplysninger, der er synlige på din skærm, eller som afspilles på din enhed, når du optager eller caster. Dette omfatter oplysninger som f.eks. adgangskoder, betalingsoplysninger, billeder, beskeder og afspillet lyd."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Vil du begynde at optage eller caste?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Vil du begynde at optage eller caste via <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Vis ikke igen"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Ryd alle"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 8a71fb2..14da101 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Απενεργοποίηση Εξοικονόμησης μπαταρίας"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"Η εφαρμογή <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> θα έχει πρόσβαση σε όλες τις πληροφορίες που εμφανίζονται στην οθόνη σας ή που αναπαράγονται από τη συσκευή σας κατά την εγγραφή ή τη μετάδοση. Αυτό περιλαμβάνει πληροφορίες όπως κωδικούς πρόσβασης, στοιχεία πληρωμής, φωτογραφίες, μηνύματα και ήχο που αναπαράγετε."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Η υπηρεσία που παρέχει αυτήν τη λειτουργία θα έχει πρόσβαση σε όλες τις πληροφορίες που εμφανίζονται στην οθόνη σας ή που αναπαράγονται από τη συσκευή σας κατά την εγγραφή ή τη μετάδοση. Αυτό περιλαμβάνει πληροφορίες όπως κωδικούς πρόσβασης, στοιχεία πληρωμής, φωτογραφίες, μηνύματα και ήχο που αναπαράγετε."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Έναρξη εγγραφής ή μετάδοσης;"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Έναρξη εγγραφής ή μετάδοσης με <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>;"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Να μην εμφανιστεί ξανά"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Διαγραφή όλων"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 1ffd1b1..5f38830 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Turn off Battery Saver"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information, such as passwords, payment details, photos, messages and audio that you play."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information, such as passwords, payment details, photos, messages and audio that you play."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Start recording or casting?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Start recording or casting with <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Don\'t show again"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 652353c..1da1df3 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Turn off Battery Saver"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information, such as passwords, payment details, photos, messages and audio that you play."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information, such as passwords, payment details, photos, messages and audio that you play."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Start recording or casting?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Start recording or casting with <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Don\'t show again"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 1ffd1b1..5f38830 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Turn off Battery Saver"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information, such as passwords, payment details, photos, messages and audio that you play."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information, such as passwords, payment details, photos, messages and audio that you play."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Start recording or casting?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Start recording or casting with <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Don\'t show again"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 1ffd1b1..5f38830 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Turn off Battery Saver"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information, such as passwords, payment details, photos, messages and audio that you play."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information, such as passwords, payment details, photos, messages and audio that you play."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Start recording or casting?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Start recording or casting with <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Don\'t show again"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index cc5ae64..fd3ff45 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‏‎‎‏‎‏‏‎‎‎‏‎‎‏‎‏‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‏‏‏‎‎‎‎‏‎‏‏‎‏‎‏‏‎‎‎‏‏‏‎Turn off Battery Saver‎‏‎‎‏‎"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‎‎‏‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>‎‏‎‎‏‏‏‎ will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages, and audio that you play.‎‏‎‎‏‎"</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‎‏‎‎‏‎‏‏‏‎‎‎‎‎‎‎‏‏‎‏‎‎‏‏‏‎‏‎‎‎‎‎‎‏‎‎‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‏‏‎The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages, and audio that you play.‎‏‎‎‏‎"</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‎‏‎‏‏‎‎‎‎‎‏‎‎‏‏‏‏‎‎‎‎‏‎‏‎‎‎‎‏‏‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‎‎‎‎‎‏‎‎‎‎Start recording or casting?‎‏‎‎‏‎"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‎‎‏‎‏‎‎‎‎‎‏‏‎‎‏‎‎‏‎‏‏‏‎‎‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‎‏‎‏‏‎‏‎‎‎‎‏‏‎‎Start recording or casting with ‎‏‎‎‏‏‎<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‎‏‎‏‎‏‎‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‎‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‏‏‎Don\'t show again‎‏‎‎‏‎"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‏‎‏‎‏‏‏‎‏‎‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎Clear all‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 713a996..eb27998f 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desactivar el Ahorro de batería"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tendrá acceso a toda la información que sea visible en la pantalla o que reproduzcas en tu dispositivo durante una grabación o transmisión. Se incluyen las contraseñas, los detalles del pago, las fotos, los mensajes y el audio que reproduzcas."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"El servicio que brinda esta función tendrá acceso a toda la información que sea visible en la pantalla o que reproduzcas en tu dispositivo durante una grabación o transmisión. Se incluyen las contraseñas, los detalles del pago, las fotos, los mensajes y el audio que reproduzcas."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"¿Deseas comenzar a grabar o transmitir contenido?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"¿Deseas iniciar una grabación o transmisión con <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"No volver a mostrar"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Borrar todo"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index ffcafae..731d727 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desactivar Ahorro de batería"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tendrá acceso a toda la información que se muestra en pantalla o se reproduce en el dispositivo mientras grabas o envías contenido, incluyendo contraseñas, detalles de pagos, fotos, mensajes y audios que reproduzcas."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"El servicio que ofrece esta función tendrá acceso a toda la información que se muestra en pantalla o se reproduce en el dispositivo mientras grabas o envías contenido, incluyendo contraseñas, detalles de pagos, fotos, mensajes y audios que reproduzcas."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"¿Quieres empezar a grabar o enviar contenido?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"¿Quieres iniciar la grabación o el envío de contenido con <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"No volver a mostrar"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Borrar todo"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index db87961..ab86e03 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Akusäästja väljalülitamine"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"Rakendus <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> saab juurdepääsu kogu teabele, mis on teie ekraanikuval nähtav või mida seadmes salvestamise või ülekande ajal esitatakse. See hõlmab teavet, nagu paroolid, maksete üksikasjad, fotod, sõnumid ja esitatav heli."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Seda funktsiooni pakkuv teenus saab juurdepääsu kogu teabele, mis on teie ekraanikuval nähtav või mida seadmes salvestamise või ülekande ajal esitatakse. See hõlmab teavet, nagu paroolid, maksete üksikasjad, fotod, sõnumid ja esitatav heli."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Kas alustada salvestamist või ülekannet?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Kas alustada rakendusega <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> salvestamist või ülekannet?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Ära kuva uuesti"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Tühjenda kõik"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 51e3d2b..18ac031 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desaktibatu bateria-aurrezlea"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"Zerbait grabatzen edo igortzen duzunean, pantailan ikus daitekeen edo gailuak erreproduzitzen duen informazio guztia atzitu ahalko du <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aplikazioak. Horrek barne hartzen ditu pasahitzak, ordainketen xehetasunak, argazkiak, mezuak eta erreproduzitzen dituzun audioak."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Zerbait grabatzen edo igortzen duzunean, pantailan ikus daitekeen edo gailuak erreproduzitzen duen informazio guztia atzitu ahalko du funtzio hori eskaintzen duen zerbitzuak. Horrek barne hartzen ditu pasahitzak, ordainketen xehetasunak, argazkiak, mezuak eta erreproduzitzen dituzun audioak."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Grabatzen edo igortzen hasi nahi duzu?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aplikazioarekin grabatzen edo igortzen hasi nahi duzu?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Ez erakutsi berriro"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Garbitu guztiak"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 20b5565..77164b7 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"«بهینه‌سازی باتری» را خاموش کنید"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> به همه اطلاعاتی که روی صفحه‌نمایش قابل‌مشاهد است و هنگام ضبط کردن یا ارسال محتوا از دستگاهتان پخش می‌شود دسترسی خواهد داشت. این شامل اطلاعاتی مانند گذرواژه‌ها، جزئیات پرداخت، عکس‌ها، پیام‌ها، و صداهایی که پخش می‌کنید می‌شود."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"سرویس ارائه‌دهنده این عملکرد به همه اطلاعاتی که روی صفحه‌نمایش قابل‌مشاهد است و هنگام ضبط کردن یا ارسال محتوا از دستگاهتان پخش می‌شود دسترسی خواهد داشت. این شامل اطلاعاتی مانند گذرواژه‌ها، جزئیات پرداخت، عکس‌ها، پیام‌ها، و صداهایی که پخش می‌کنید می‌شود."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ضبط یا ارسال محتوا شروع شود؟"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"ضبط یا ارسال محتوا با <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> شروع شود؟"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"دوباره نشان داده نشود"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"پاک کردن همه موارد"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 945e63d..e70b4d5 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Poista virransäästö käytöstä"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> saa pääsyn kaikkiin näytölläsi näkyviin tietoihin ja tietoihin laitteesi toistamasta sisällöstä tallennuksen tai striimauksen aikana. Näitä tietoja ovat esimerkiksi salasanat, maksutiedot, kuvat, viestit ja toistettava audiosisältö."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Ominaisuuden tarjoavalla palvelulla on pääsy kaikkiin näytölläsi näkyviin tietoihin ja tietoihin laitteesi toistamasta sisällöstä tallennuksen tai striimauksen aikana. Näitä tietoja ovat esimerkiksi salasanat, maksutiedot, kuvat, viestit ja toistettava audiosisältö."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Aloitetaanko tallentaminen tai striimaus?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Haluatko, että <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aloittaa tallennuksen tai striimauksen?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Älä näytä uudelleen"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Poista kaikki"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index ac27ea8..ead29c0 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Désactiver la fonction Économie d\'énergie"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aura accès à toute l\'information visible sur votre écran ou qui joue sur votre appareil durant l\'enregistrement ou la diffusion. Cela comprend des renseignements comme les mots de passe, les détails du paiement, les photos, les messages et l\'audio que vous faites jouer."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Le service offrant cette fonction aura accès à toute l\'information visible sur votre écran ou qui joue sur votre appareil durant l\'enregistrement ou la diffusion. Cela comprend des renseignements comme les mots de passe, les détails du paiement, les photos, les messages et l\'audio que vous faites jouer."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Commencer à enregistrer ou à diffuser?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Commencer à enregistrer ou à diffuser avec <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Ne plus afficher"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Tout effacer"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index d88201d..b701276 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Désactiver l\'économiseur de batterie"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aura accès à toutes les informations visibles sur votre écran ou lues depuis votre appareil lors d\'un enregistrement ou d\'une diffusion de contenu. Par exemple, vos mots de passe, vos données de paiement, vos photos, vos messages ou encore vos contenus audio lus."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Le service fournissant cette fonctionnalité aura accès à toutes les informations visibles sur votre écran ou lues depuis votre appareil lors d\'un enregistrement ou d\'une diffusion de contenu. Par exemple, vos mots de passe, vos données de paiement, vos photos, vos messages ou encore vos contenus audio lus."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Démarrer l\'enregistrement ou la diffusion ?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Démarrer l\'enregistrement ou la diffusion avec <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Ne plus afficher"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Tout effacer"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 0cbb0bc..de6b3793 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"બૅટરી સેવર બંધ કરો"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"રેકૉર્ડ અથવા કાસ્ટ કરતી વખતે, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>ને તમારી સ્ક્રીન પર દેખાતી હોય અથવા તમારા ડિવાઇસ પર ચલાવવામાં આવતી હોય તેવી બધી માહિતીનો ઍક્સેસ હશે. આમાં પાસવર્ડ, ચુકવણીની વિગતો, ફોટા, સંદેશા અને તમે ચલાવો છો તે ઑડિયો જેવી માહિતીનો સમાવેશ થાય છે."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"રેકૉર્ડ અથવા કાસ્ટ કરતી વખતે, આ સુવિધા આપતી સેવાને તમારી સ્ક્રીન પર દેખાતી હોય અથવા તમારા ડિવાઇસ પર ચલાવવામાં આવતી હોય તેવી બધી માહિતીનો ઍક્સેસ હશે. આમાં પાસવર્ડ, ચુકવણીની વિગતો, ફોટા, સંદેશા અને તમે ચલાવો છો તે ઑડિયો જેવી માહિતીનો સમાવેશ થાય છે."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"શું રેકૉર્ડ અથવા કાસ્ટ કરવાનું શરૂ કરીએ?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> વડે રેકૉર્ડ અથવા કાસ્ટ કરવાનું શરૂ કરીએ?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"ફરીથી બતાવશો નહીં"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"બધુ સાફ કરો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 23a5126..706f8b3 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -946,10 +946,7 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"सिस्टम नेविगेशन अपडेट हो गया. बदलाव करने के लिए \'सेटिंग\' पर जाएं."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"सिस्टम नेविगेशन अपडेट करने के लिए \'सेटिंग\' में जाएं"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्टैंडबाई"</string>
-    <!-- no translation found for magnification_overlay_title (6584179429612427958) -->
-    <skip />
-    <!-- no translation found for magnification_window_title (4863914360847258333) -->
-    <skip />
-    <!-- no translation found for magnification_controls_title (8421106606708891519) -->
-    <skip />
+    <string name="magnification_overlay_title" msgid="6584179429612427958">"Magnification Overlay Window"</string>
+    <string name="magnification_window_title" msgid="4863914360847258333">"स्क्रीन को बड़ा करके दिखाने वाली विंडो"</string>
+    <string name="magnification_controls_title" msgid="8421106606708891519">"स्क्रीन को बड़ा करके दिखाने वाली विंडो के नियंत्रण"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 42f0df5..bf027fb 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -468,8 +468,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Isključite Štednju baterije"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> imat će pristup svim podacima koji su vidljivi na vašem zaslonu ili koji se reproduciraju s vašeg uređaja tijekom snimanja ili emitiranja. To uključuje podatke kao što su zaporke, podaci o plaćanju, fotografije, poruke i audiozapisi koje reproducirate."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Usluga koja pruža ovu funkcionalnost imat će pristup svim podacima koji su vidljivi na vašem zaslonu ili koji se reproduciraju s vašeg uređaja tijekom snimanja ili emitiranja. To uključuje podatke kao što su zaporke, podaci o plaćanju, fotografije, poruke i audiozapisi koje reproducirate."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Započeti snimanje ili emitiranje?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Započeti snimanje ili emitiranja pomoću aplikacije <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Ne prikazuj ponovo"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Izbriši sve"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 7a5eadf..90c8a1a 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Akkumulátorkímélő mód kikapcsolása"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"A(z) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> hozzáfér majd minden olyan információhoz, amely látható az Ön képernyőjén, vagy amelyet az Ön eszközéről játszanak le rögzítés vagy átküldés során. Ez olyan információkat is tartalmaz, mint a jelszavak, a fizetési részletek, fotók, üzenetek és lejátszott audiotartalmak."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"A funkciót biztosító szolgáltatás hozzáfér majd minden olyan információhoz, amely látható az Ön képernyőjén, illetve amelyet az Ön eszközéről játszanak le rögzítés vagy átküldés közben. Ez olyan információkat is tartalmaz, mint a jelszavak, a fizetési részletek, fotók, üzenetek és lejátszott audiotartalmak."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Biztosan elkezdi a rögzítést vagy az átküldést?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Elkezdi a rögzítést vagy átküldést a következővel: <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Ne jelenjen meg többé"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Az összes törlése"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 9f24d74..95e4010 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Slökkva á rafhlöðusparnaði"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> mun hafa aðgang að öllum upplýsingum sem sjást á skjánum eða eru spilaðar í tækinu á meðan upptaka eða útsending er í gangi. Þar á meðal eru upplýsingar á borð við aðgangsorð, greiðsluupplýsingar, myndir, skilaboð og hljóð sem þú spilar."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Þjónustan sem býður upp á þennan eiginleika mun hafa aðgang að öllum upplýsingum sem sjást á skjánum eða eru spilaðar í tækinu á meðan upptaka eða útsending er í gangi. Þar á meðal eru upplýsingar á borð við aðgangsorð, greiðsluupplýsingar, myndir, skilaboð og hljóð sem þú spilar."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Viltu hefja upptöku eða útsendingu?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Viltu hefja upptöku eða útsendingu með <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Ekki sýna þetta aftur"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Hreinsa allt"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 9b2faa5..4cec980 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Disattiva Risparmio energetico"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> avrà accesso a tutte le informazioni visibili sul tuo schermo o riprodotte dal tuo dispositivo durante la registrazione o la trasmissione. Sono incluse informazioni quali password, dettagli sui pagamenti, foto, messaggi e audio riprodotto."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Il servizio che offre questa funzione avrà accesso a tutte le informazioni visibili sul tuo schermo o riprodotte dal tuo dispositivo durante la registrazione o la trasmissione. Sono incluse informazioni quali password, dettagli sui pagamenti, foto, messaggi e audio riprodotto."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Vuoi avviare la registrazione o la trasmissione?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Vuoi avviare la registrazione o la trasmissione con <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Non mostrare più"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Cancella tutto"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 474327d..949c8db 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -471,8 +471,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"כיבוי תכונת החיסכון בסוללה"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"‏לאפליקציה <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> תהיה גישה לכל הפרטים שגלויים במסך שלך או מופעלים מהמכשיר שלך בזמן הקלטה או העברה (cast). זה כולל פרטים כמו סיסמאות, פרטי תשלום, תמונות, הודעות ואודיו שמושמע מהמכשיר."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"‏לשירות שמספק את הפונקציה הזו תהיה גישה לכל הפרטים שגלויים במסך שלך או מופעלים מהמכשיר שלך בזמן הקלטה או העברה (cast). זה כולל פרטים כמו סיסמאות, פרטי תשלום, תמונות, הודעות ואודיו שמושמע מהמכשיר."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"‏להתחיל להקליט או להעביר (cast)?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"‏להתחיל להקליט או להעביר (cast) באמצעות <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"אל תציג שוב"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"ניקוי הכל"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 60b4fe4..49d678b 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -471,8 +471,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Išjungti Akumuliatoriaus tausojimo priemonę"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"„<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“ galės pasiekti visą informaciją, matomą ekrane ir leidžiamą iš įrenginio įrašant ar perduodant turinį. Tai apima įvairią informaciją, pvz., slaptažodžius, išsamią mokėjimo informaciją, nuotraukas, pranešimus ir leidžiamus garso įrašus."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Šią funkcija teikianti paslauga galės pasiekti visą informaciją, matomą ekrane ir leidžiamą iš įrenginio įrašant ar perduodant turinį. Tai apima įvairią informaciją, pvz., slaptažodžius, išsamią mokėjimo informaciją, nuotraukas, pranešimus ir leidžiamus garso įrašus."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Pradėti įrašyti ar perduoti turinį?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Pradėti įrašyti ar perduoti turinį naudojant „<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Daugiau neberodyti"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Viską išvalyti"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 5233b16..0294a1f 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Исклучете го штедачот на батерија"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ќе има пристап до сите информации што се видливи на екранот или пуштени од вашиот уред додека се снима или емитува. Ова вклучува информации како, на пример, лозинки, детали на исплатата, фотографии, пораки и аудио што го пуштате."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Услугата што ја обезбедува функцијава ќе има пристап до сите информации што се видливи на екранот или пуштени од вашиот уред додека се снима или емитува. Ова вклучува информации како, на пример, лозинки, детали на исплатата, фотографии, пораки и аудио што го пуштате."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Да почне снимање или емитување?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Да почне снимање или емитување со <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Не покажувај повторно"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Избриши сѐ"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 862f63e..e5497ea 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Тэжээл хэмнэгчийг унтраах"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> нь бичлэг хийх эсвэл дамжуулах үед таны дэлгэц дээр харагдах эсвэл таны төхөөрөмжөөс тоглуулах бүх мэдээлэлд хандах боломжтой байна. Үүнд нууц үг, төлбөрийн дэлгэрэнгүй, зураг болон таны тоглуулдаг аудио зэрэг мэдээлэл багтана."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Энэ функцийг ажиллуулж байгаа үйлчилгээ нь бичлэг хийх эсвэл дамжуулах үед таны дэлгэц дээр харагдах эсвэл таны төхөөрөмжөөс тоглуулах бүх мэдээлэлд хандах боломжтой байна. Үүнд нууц үг, төлбөрийн дэлгэрэнгүй, зураг болон таны тоглуулдаг аудио зэрэг мэдээлэл багтана."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Бичлэг хийх эсвэл дамжуулахыг эхлүүлэх үү?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>-тай бичлэг хийж эсвэл дамжуулж эхлэх үү?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Дахиж үл харуулах"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Бүгдийг арилгах"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 9a8b50fc..b632bcd 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Matikan Penjimat Bateri"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> akan mempunyai akses kepada semua maklumat yang kelihatan pada skrin anda atau yang dimainkan daripada peranti anda semasa merakam atau membuat penghantaran. Ini termasuklah maklumat seperti kata laluan, butiran pembayaran, foto, mesej dan audio yang anda mainkan."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Perkhidmatan yang menyediakan fungsi ini akan mempunyai akses kepada semua maklumat yang kelihatan pada skrin anda atau dimainkan daripada peranti anda semasa merakam atau membuat penghantaran. Ini termasuklah maklumat seperti kata laluan, butiran pembayaran, foto, mesej dan audio yang anda mainkan."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Mulakan rakaman atau penghantaran?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Mulakan rakaman atau penghantaran dengan <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Jangan tunjukkan lagi"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Kosongkan semua"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index ef6bc47..ba6b0ed 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"ब्याट्री सेभर निष्क्रिय पार्नुहोस्"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ले तपाईंको स्क्रिनमा देख्न सकिने सबै जानकारी अथवा रेकर्ड वा cast गर्दा तपाईंको यन्त्रबाट प्ले गरिएका कुरामाथि पहुँच राख्न सक्ने छ। यसअन्तर्गत पासवर्ड, भुक्तानीका विवरण, तस्बिर, सन्देश र तपाईंले प्ले गर्ने अडियो जस्ता जानकारी समावेश हुन्छन्।"</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"यो कार्य प्रदान गर्ने सेवाले तपाईंको स्क्रिनमा देख्न सकिने सबै जानकारी अथवा रेकर्ड वा cast गर्दा तपाईंको यन्त्रबाट प्ले गरिएका कुरामाथि पहुँच राख्न सक्ने छ। यसअन्तर्गत पासवर्ड, भुक्तानीका विवरण, तस्बिर, सन्देश र तपाईंले प्ले गर्ने अडियो जस्ता जानकारी समावेश हुन्छन्।"</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"रेकर्ड गर्न वा cast गर्न थाल्ने हो?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> मार्फत रेकर्ड गर्न वा cast गर्न थाल्ने हो?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"फेरि नदेखाउनुहोस्"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"सबै हटाउनुहोस्"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 5d57927..638fcad 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Batterijbesparing uitschakelen"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> krijgt toegang tot alle informatie die zichtbaar is op je scherm of die wordt afgespeeld vanaf je apparaat tijdens het opnemen of casten. Dit omvat informatie zoals wachtwoorden, betalingsgegevens, foto\'s, berichten en audio die je afspeelt."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"De service die deze functie levert, krijgt toegang tot alle informatie die zichtbaar is op je scherm of die wordt afgespeeld vanaf je apparaat tijdens het opnemen of casten. Dit omvat informatie zoals wachtwoorden, betalingsgegevens, foto\'s, berichten en audio die je afspeelt."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Beginnen met opnemen of casten?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Beginnen met opnemen of casten met <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Niet opnieuw weergeven"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Alles wissen"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index d3f5ae2..307d417 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -471,8 +471,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Wyłącz Oszczędzanie baterii"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"Podczas nagrywania i przesyłania aplikacja <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> będzie mieć dostęp do wszystkich informacji widocznych na ekranie lub odtwarzanych na urządzeniu. Dotyczy to m.in. haseł, szczegółów płatności, zdjęć, wiadomości i odtwarzanych dźwięków."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Podczas nagrywania i przesyłania usługa udostępniająca tę funkcję będzie miała dostęp do wszystkich informacji widocznych na ekranie lub odtwarzanych na urządzeniu. Dotyczy to m.in. haseł, szczegółów płatności, zdjęć, wiadomości i odtwarzanych dźwięków."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Rozpocząć nagrywanie lub przesyłanie?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Rozpocząć nagrywanie lub przesyłanie za pomocą aplikacji <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Nie pokazuj ponownie"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Usuń wszystkie"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 4d4a607..c1dd243 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desativar a Economia de bateria"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"O app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> terá acesso a todas as informações visíveis na tela ou tocadas no dispositivo, como gravação ou transmissão Isso inclui informações como senhas, detalhes de pagamento, fotos, mensagens e áudio que você toca."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"O serviço que oferece essa função terá acesso a todas as informações visíveis na tela ou tocadas no dispositivo durante uma gravação ou transmissão. Isso inclui informações como senhas, detalhes de pagamento, fotos, mensagens e áudio que você toca."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Iniciar gravação ou transmissão?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Iniciar gravação ou transmissão com o app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Não mostrar novamente"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Limpar tudo"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 1f23159..9a5a4b3 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desativar a Poupança de bateria"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"A aplicação <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> terá acesso a todas as informações que estiverem visíveis no ecrã ou que forem reproduzidas a partir do dispositivo durante a gravação ou transmissão. Isto inclui informações como palavras-passe, detalhes de pagamentos, fotos, mensagens e áudio reproduzido."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"O serviço que fornece esta função terá acesso a todas as informações que estiverem visíveis no ecrã ou que forem reproduzidas a partir do dispositivo durante a gravação ou transmissão. Isto inclui informações como palavras-passe, detalhes de pagamentos, fotos, mensagens e áudio reproduzido."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Pretende começar a gravar ou a transmitir?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Pretende começar a gravar ou a transmitir com a aplicação <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Não mostrar de novo"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Limpar tudo"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 4d4a607..c1dd243 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desativar a Economia de bateria"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"O app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> terá acesso a todas as informações visíveis na tela ou tocadas no dispositivo, como gravação ou transmissão Isso inclui informações como senhas, detalhes de pagamento, fotos, mensagens e áudio que você toca."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"O serviço que oferece essa função terá acesso a todas as informações visíveis na tela ou tocadas no dispositivo durante uma gravação ou transmissão. Isso inclui informações como senhas, detalhes de pagamento, fotos, mensagens e áudio que você toca."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Iniciar gravação ou transmissão?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Iniciar gravação ou transmissão com o app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Não mostrar novamente"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Limpar tudo"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 6fc30de..c38c855 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -471,8 +471,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Vypnúť šetrič batérie"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"Povolenie <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> bude mať prístup k všetkým informáciám zobrazovaným na obrazovke alebo prehrávaným v zariadení počas nahrávania či prenosu. Patria medzi ne informácie, akými sú napríklad heslá, platobné podrobnosti, fotky, správy a prehrávaný zvuk."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Služba poskytujúca túto funkciu bude mať prístup k všetkým informáciám zobrazovaným na obrazovke alebo prehrávaným v zariadení počas nahrávania či prenosu. Patria medzi ne informácie, akými sú napríklad heslá, platobné podrobnosti, fotky, správy a prehrávaný zvuk."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Chcete začať nahrávanie alebo prenos?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Chcete spustiť nahrávanie alebo prenos s aktivovaným povolením <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Nabudúce nezobrazovať"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Vymazať všetko"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 730f4b0..445f8ca4 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Çaktivizo \"Kursyesin e baterisë\""</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> do të ketë qasje te të gjitha informacionet që janë të dukshme në ekran ose që luhen nga pajisja jote gjatë regjistrimit ose transmetimit. Kjo përfshin informacione si p.sh. fjalëkalimet, detajet e pagesave, fotografitë, mesazhet dhe audion që luan ti."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Shërbimi që e ofron këtë funksion do të ketë qasje te të gjitha informacionet që janë të dukshme në ekran ose që luhen nga pajisja jote gjatë regjistrimit ose transmetimit. Kjo përfshin informacione si p.sh. fjalëkalimet, detajet e pagesave, fotografitë, mesazhet dhe audion që luan ti."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Do të fillosh regjistrimin ose transmetimin?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Fillo regjistrimin ose transmetimin me <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Mos e shfaq sërish"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Pastroji të gjitha"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 3660b06..acff269 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -468,8 +468,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Искључи Уштеду батерије"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ће имати приступ свим информацијама које се приказују на екрану или репродукују са уређаја током снимања или пребацивања. То обухвата информације попут лозинки, информација о плаћању, слика, порука и звука који пуштате."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Услуга која пружа ову функцију ће имати приступ свим информацијама које се приказују на екрану или репродукују са уређаја током снимања или пребацивања. То обухвата информације попут лозинки, информација о плаћању, слика, порука и звука који пуштате."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Желите да почнете снимање или пребацивање?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Желите да почнете снимање или пребацивање помоћу апликације <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Не приказуј поново"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Обриши све"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 67e2e04..d63206a 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Inaktivera batterisparläget"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> får åtkomst till all information som visas på skärmen eller spelas upp från enheten när du spelar in eller castar. Detta omfattar uppgifter som lösenord, betalningsinformation, foton, meddelanden och ljud som du spelar upp."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Den tjänst som tillhandahåller funktionen får åtkomst till all information som visas på skärmen eller spelas upp från enheten när du spelar in eller castar. Detta omfattar uppgifter som lösenord, betalningsinformation, foton, meddelanden och ljud som du spelar upp."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Vill du börja spela in eller casta?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Vill du börja spela in eller casta med <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Visa inte igen"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Rensa alla"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 94377d7..3640c80 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -471,8 +471,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Вимкнути режим економії заряду акумулятора"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"Додаток <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> матиме доступ до всієї інформації, яка з\'являється на екрані або відтворюється на пристрої під час запису чи трансляції, зокрема до паролів, інформації про платежі, фотографій, повідомлень і аудіофайлів."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Сервіс, що надає цю функцію, матиме доступ до всієї інформації, яка з\'являється на екрані або відтворюється на пристрої під час запису чи трансляції, зокрема до паролів, інформації про платежі, фотографій, повідомлень і аудіофайлів."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Почати запис або трансляцію?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Почати запис або трансляцію за допомогою додатка <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Більше не показувати"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Очистити все"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index ec11d1f..fdc618b 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"بیٹری سیور آف کریں"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> کو ان تمام معلومات تک رسائی حاصل ہوگی جو آپ کی اسکرین پر مرئی ہے یا ریکارڈنگ یا کاسٹنگ کے دوران آپ کے آلے سے چلائے گئے ہوں۔ اس میں پاس ورڈز، ادائیگی کی تفصیلات، تصاویر، پیغامات، اور آپ کے ذریعے چلائی جانے والی آڈیو جیسی معلومات شامل ہے۔"</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"یہ فنکشن فراہم کرنے والی سروس کو ان تمام معلومات تک رسائی حاصل ہوگی جو آپ کی اسکرین پر مرئی ہے یا ریکارڈنگ یا کاسٹنگ کے دوران آپ کے آلے سے چلائے گئے ہوں۔ اس میں پاس ورڈز، ادائیگی کی تفصیلات، تصاویر، پیغامات، اور آپ کے ذریعے چلائی جانے والی آڈیو جیسی معلومات شامل ہے۔"</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ریکارڈنگ یا کاسٹنگ شروع کریں؟"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> کے ذریعے ریکارڈنگ یا کاسٹنگ شروع کریں؟"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"دوبارہ نہ دکھائیں"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"سبھی کو صاف کریں"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 10348fb..dae6eb1 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"關閉省電模式"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"在錄影或投放時,「<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>」可以存取螢幕顯示或裝置播放的任何資料,當中包括密碼、付款詳情、相片、訊息和播放的語音等。"</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"在錄影或投放時,此功能的服務供應商可以存取螢幕顯示或裝置播放的任何資料,當中包括密碼、付款詳情、相片、訊息和播放的語音等。"</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"要開始錄影或投放嗎?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"要使用「<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>」開始錄影或投放嗎?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"不用再顯示"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"全部清除"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 7ae14cc..5353018 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -465,8 +465,7 @@
     <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Vala isilondolozi sebhethri"</string>
     <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> izithola ukufinyelela kulo lonke ulwazi olubonakalayo esikrinini sakho noma idlalwe kusuka kudivayisi yakho ngenkathi urekhoda noma usakaza. Lokhu kubandakanya ulwazi olufana namaphasiwedi, imininingwane yenkokhelo, izithombe, imilayezo, nomsindo owudlalayo."</string>
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Isevisi enikezela ngalo msebenzi izothola ukufinyelela kulo lonke ulwazi olubonakalayo esikrinini sakho noma oludlalwa kusuka kudivayisi yakho ngenkathi urekhoda noma usakaza. Lokhu kubandakanya ulwazi olufana namaphasiwedi, imininingwane yenkokhelo, izithombe, imilayezo, nomsindo owudlalayo."</string>
-    <!-- no translation found for media_projection_dialog_service_title (2888507074107884040) -->
-    <skip />
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Qala ukurekhoda noma ukusakaza?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Qala ukurekhoda noma ukusakaza nge-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
     <string name="media_projection_remember_text" msgid="6896767327140422951">"Ungabonisi futhi"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Sula konke"</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index b960de5..35a65aa 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -26,8 +26,6 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Color;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -37,7 +35,6 @@
 import android.view.WindowManager;
 import android.widget.ImageView;
 
-import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
@@ -258,12 +255,22 @@
 
         @Override
         public void run() {
-            try {
-                if (DEBUG) {
-                    Log.v(TAG, "call supplyPinReportResultForSubscriber(subid=" + mSubId + ")");
-                }
-                final int[] result = ITelephony.Stub.asInterface(ServiceManager
-                        .checkService("phone")).supplyPinReportResultForSubscriber(mSubId, mPin);
+            if (DEBUG) {
+                Log.v(TAG, "call supplyPinReportResultForSubscriber(subid=" + mSubId + ")");
+            }
+            TelephonyManager telephonyManager =
+                    ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE))
+                            .createForSubscriptionId(mSubId);
+            final int[] result = telephonyManager.supplyPinReportResult(mPin);
+            if (result == null || result.length == 0) {
+                Log.e(TAG, "Error result for supplyPinReportResult.");
+                post(new Runnable() {
+                    @Override
+                    public void run() {
+                        onSimCheckResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1);
+                    }
+                });
+            } else {
                 if (DEBUG) {
                     Log.v(TAG, "supplyPinReportResult returned: " + result[0] + " " + result[1]);
                 }
@@ -273,14 +280,6 @@
                         onSimCheckResponse(result[0], result[1]);
                     }
                 });
-            } catch (RemoteException e) {
-                Log.e(TAG, "RemoteException for supplyPinReportResult:", e);
-                post(new Runnable() {
-                    @Override
-                    public void run() {
-                        onSimCheckResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1);
-                    }
-                });
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index 7e08ab3..dc68115 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -25,8 +25,6 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Color;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -36,7 +34,6 @@
 import android.view.WindowManager;
 import android.widget.ImageView;
 
-import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
@@ -318,10 +315,20 @@
 
         @Override
         public void run() {
-            try {
-                if (DEBUG) Log.v(TAG, "call supplyPukReportResult()");
-                final int[] result = ITelephony.Stub.asInterface(ServiceManager
-                    .checkService("phone")).supplyPukReportResultForSubscriber(mSubId, mPuk, mPin);
+            if (DEBUG) Log.v(TAG, "call supplyPukReportResult()");
+            TelephonyManager telephonyManager =
+                    ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE))
+                            .createForSubscriptionId(mSubId);
+            final int[] result = telephonyManager.supplyPukReportResult(mPuk, mPin);
+            if (result == null || result.length == 0) {
+                Log.e(TAG, "Error result for supplyPukReportResult.");
+                post(new Runnable() {
+                    @Override
+                    public void run() {
+                        onSimLockChangedResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1);
+                    }
+                });
+            } else {
                 if (DEBUG) {
                     Log.v(TAG, "supplyPukReportResult returned: " + result[0] + " " + result[1]);
                 }
@@ -331,14 +338,6 @@
                         onSimLockChangedResponse(result[0], result[1]);
                     }
                 });
-            } catch (RemoteException e) {
-                Log.e(TAG, "RemoteException for supplyPukReportResult:", e);
-                post(new Runnable() {
-                    @Override
-                    public void run() {
-                        onSimLockChangedResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1);
-                    }
-                });
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 4728327..02a4521 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -694,7 +694,7 @@
 
     public boolean isFalseGesture(MotionEvent ev) {
         boolean falsingDetected = mCallback.isAntiFalsingNeeded();
-        if (mFalsingManager.isClassiferEnabled()) {
+        if (mFalsingManager.isClassifierEnabled()) {
             falsingDetected = falsingDetected && mFalsingManager.isFalseTouch();
         } else {
             falsingDetected = falsingDetected && !mTouchAboveFalsingThreshold;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
index 995b35f..fdeaf1f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
@@ -134,7 +134,8 @@
                 if (isStack) {
                     mViewPositionOnTouchDown.set(mStack.getStackPosition());
                     mStack.onDragStart();
-                    if (!mStack.isShowingBubbleMenu() && !mStack.isExpanded()) {
+                    if (!mStack.isShowingBubbleMenu() && !mStack.isExpanded()
+                            && BubbleExperimentConfig.allowBubbleScreenshotMenu(mContext)) {
                         mShowBubbleMenuRunnable = mStack::showBubbleMenu;
                         mStack.postDelayed(mShowBubbleMenuRunnable,
                                 ViewConfiguration.getLongPressTimeout());
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
index ea175ed..099909d 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
@@ -90,7 +90,7 @@
     }
 
     @Override
-    public boolean isClassiferEnabled() {
+    public boolean isClassifierEnabled() {
         return mIsClassiferEnabled;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
index eb014ed..d6faed5 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerImpl.java
@@ -213,7 +213,7 @@
 
     private void onSessionStart() {
         if (FalsingLog.ENABLED) {
-            FalsingLog.i("onSessionStart", "classifierEnabled=" + isClassiferEnabled());
+            FalsingLog.i("onSessionStart", "classifierEnabled=" + isClassifierEnabled());
             clearPendingWtf();
         }
         mBouncerOn = false;
@@ -246,7 +246,7 @@
         }
     }
 
-    public boolean isClassiferEnabled() {
+    public boolean isClassifierEnabled() {
         return mHumanInteractionClassifier.isEnabled();
     }
 
@@ -544,7 +544,7 @@
 
     public void dump(PrintWriter pw) {
         pw.println("FALSING MANAGER");
-        pw.print("classifierEnabled="); pw.println(isClassiferEnabled() ? 1 : 0);
+        pw.print("classifierEnabled="); pw.println(isClassifierEnabled() ? 1 : 0);
         pw.print("mSessionActive="); pw.println(mSessionActive ? 1 : 0);
         pw.print("mBouncerOn="); pw.println(mSessionActive ? 1 : 0);
         pw.print("mState="); pw.println(StatusBarState.toShortString(mState));
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
index f475948..b2131e7 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerProxy.java
@@ -21,8 +21,8 @@
 import android.content.Context;
 import android.hardware.SensorManager;
 import android.net.Uri;
-import android.os.Handler;
 import android.provider.DeviceConfig;
+import android.util.DisplayMetrics;
 import android.view.MotionEvent;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -32,6 +32,7 @@
 import com.android.systemui.classifier.brightline.FalsingDataProvider;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.UiBackground;
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.FalsingPlugin;
 import com.android.systemui.plugins.PluginListener;
@@ -56,19 +57,22 @@
     private static final String PROXIMITY_SENSOR_TAG = "FalsingManager";
 
     private final ProximitySensor mProximitySensor;
+    private final DisplayMetrics mDisplayMetrics;
     private FalsingManager mInternalFalsingManager;
     private DeviceConfig.OnPropertiesChangedListener mDeviceConfigListener;
     private final DeviceConfigProxy mDeviceConfig;
     private boolean mBrightlineEnabled;
+    private final DockManager mDockManager;
     private Executor mUiBgExecutor;
 
     @Inject
-    FalsingManagerProxy(Context context, PluginManager pluginManager,
-            @Main Handler handler,
-            ProximitySensor proximitySensor,
-            DeviceConfigProxy deviceConfig,
+    FalsingManagerProxy(Context context, PluginManager pluginManager, @Main Executor executor,
+            DisplayMetrics displayMetrics, ProximitySensor proximitySensor,
+            DeviceConfigProxy deviceConfig, DockManager dockManager,
             @UiBackground Executor uiBgExecutor) {
+        mDisplayMetrics = displayMetrics;
         mProximitySensor = proximitySensor;
+        mDockManager = dockManager;
         mUiBgExecutor = uiBgExecutor;
         mProximitySensor.setTag(PROXIMITY_SENSOR_TAG);
         mProximitySensor.setSensorDelay(SensorManager.SENSOR_DELAY_GAME);
@@ -78,7 +82,7 @@
         setupFalsingManager(context);
         mDeviceConfig.addOnPropertiesChangedListener(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
-                handler::post,
+                executor,
                 mDeviceConfigListener
         );
 
@@ -125,10 +129,11 @@
             mInternalFalsingManager = new FalsingManagerImpl(context, mUiBgExecutor);
         } else {
             mInternalFalsingManager = new BrightLineFalsingManager(
-                    new FalsingDataProvider(context.getResources().getDisplayMetrics()),
+                    new FalsingDataProvider(mDisplayMetrics),
                     Dependency.get(KeyguardUpdateMonitor.class),
                     mProximitySensor,
-                    mDeviceConfig
+                    mDeviceConfig,
+                    mDockManager
             );
         }
     }
@@ -182,8 +187,8 @@
     }
 
     @Override
-    public boolean isClassiferEnabled() {
-        return mInternalFalsingManager.isClassiferEnabled();
+    public boolean isClassifierEnabled() {
+        return mInternalFalsingManager.isClassifierEnabled();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
index bd0906a..b2e61a2 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/brightline/BrightLineFalsingManager.java
@@ -25,17 +25,21 @@
 import android.view.MotionEvent;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.classifier.Classifier;
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.sensors.ProximitySensor;
 
 import java.io.PrintWriter;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
+import java.util.Queue;
 
 /**
  * FalsingManager designed to make clear why a touch was rejected.
@@ -44,16 +48,20 @@
 
     static final boolean DEBUG = false;
     private static final String TAG = "FalsingManager";
+    private static final int RECENT_INFO_LOG_SIZE = 20;
 
     private final FalsingDataProvider mDataProvider;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final ProximitySensor mProximitySensor;
+    private final DockManager mDockManager;
     private boolean mSessionStarted;
     private MetricsLogger mMetricsLogger;
     private int mIsFalseTouchCalls;
     private boolean mShowingAod;
     private boolean mScreenOn;
     private boolean mJustUnlockedWithFace;
+    private static final Queue<String> RECENT_INFO_LOG =
+            new ArrayDeque<>(RECENT_INFO_LOG_SIZE + 1);
 
     private final List<FalsingClassifier> mClassifiers;
 
@@ -71,14 +79,14 @@
                 }
             };
 
-    public BrightLineFalsingManager(
-            FalsingDataProvider falsingDataProvider,
-            KeyguardUpdateMonitor keyguardUpdateMonitor,
-            ProximitySensor proximitySensor,
-            DeviceConfigProxy deviceConfigProxy) {
+    public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider,
+            KeyguardUpdateMonitor keyguardUpdateMonitor, ProximitySensor proximitySensor,
+            DeviceConfigProxy deviceConfigProxy,
+            DockManager dockManager) {
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mDataProvider = falsingDataProvider;
         mProximitySensor = proximitySensor;
+        mDockManager = dockManager;
         mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
 
         mMetricsLogger = new MetricsLogger();
@@ -134,29 +142,30 @@
     }
 
     @Override
-    public boolean isClassiferEnabled() {
+    public boolean isClassifierEnabled() {
         return true;
     }
 
     @Override
     public boolean isFalseTouch() {
-        boolean r = !mJustUnlockedWithFace && mClassifiers.stream().anyMatch(falsingClassifier -> {
-            boolean result = falsingClassifier.isFalseTouch();
-            if (result) {
-                logInfo(String.format(
-                        (Locale) null,
-                        "{classifier=%s, interactionType=%d}",
-                        falsingClassifier.getClass().getName(),
-                        mDataProvider.getInteractionType()));
-                String reason = falsingClassifier.getReason();
-                if (reason != null) {
-                    logInfo(reason);
-                }
-            } else {
-                logDebug(falsingClassifier.getClass().getName() + ": false");
-            }
-            return result;
-        });
+        boolean r = !mJustUnlockedWithFace && !mDockManager.isDocked()
+                && mClassifiers.stream().anyMatch(falsingClassifier -> {
+                    boolean result = falsingClassifier.isFalseTouch();
+                    if (result) {
+                        logInfo(String.format(
+                                (Locale) null,
+                                "{classifier=%s, interactionType=%d}",
+                                falsingClassifier.getClass().getName(),
+                                mDataProvider.getInteractionType()));
+                        String reason = falsingClassifier.getReason();
+                        if (reason != null) {
+                            logInfo(reason);
+                        }
+                    } else {
+                        logDebug(falsingClassifier.getClass().getName() + ": false");
+                    }
+                    return result;
+                });
 
         logDebug("Is false touch? " + r);
 
@@ -336,7 +345,18 @@
     }
 
     @Override
-    public void dump(PrintWriter printWriter) {
+    public void dump(PrintWriter pw) {
+        IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
+        ipw.println("BRIGHTLINE FALSING MANAGER");
+        ipw.print("classifierEnabled="); pw.println(isClassifierEnabled() ? 1 : 0);
+        ipw.print("mJustUnlockedWithFace="); pw.println(mJustUnlockedWithFace ? 1 : 0);
+        ipw.print("isDocked="); pw.println(mDockManager.isDocked() ? 1 : 0);
+        ipw.println();
+        ipw.println("Recent falsing info:");
+        ipw.increaseIndent();
+        for (String msg : RECENT_INFO_LOG) {
+            ipw.println(msg);
+        }
     }
 
     @Override
@@ -357,6 +377,10 @@
 
     static void logInfo(String msg) {
         Log.i(TAG, msg);
+        RECENT_INFO_LOG.add(msg);
+        while (RECENT_INFO_LOG.size() > RECENT_INFO_LOG_SIZE) {
+            RECENT_INFO_LOG.remove();
+        }
     }
 
     static void logError(String msg) {
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index eb19571..c8cf02a 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -585,10 +585,10 @@
                                 resolver,
                                 Global.LOW_POWER_MODE_TRIGGER_LEVEL,
                                 batterySaverTriggerLevel);
-                        Secure.putInt(
+                        Secure.putIntForUser(
                                 resolver,
                                 Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
-                                1);
+                                1, UserHandle.USER_CURRENT);
                     });
         } else {
             d.setTitle(R.string.battery_saver_confirmation_title);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 5abca6b..7ad07c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -168,7 +168,8 @@
         mStatusBarStateController = statusBarStateController;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mDockManager = dockManager;
-        mDockManager.addAlignmentStateListener(this::handleAlignStateChanged);
+        mDockManager.addAlignmentStateListener(
+                alignState -> mHandler.post(() -> handleAlignStateChanged(alignState)));
         // lock icon is not used on all form factors.
         if (mLockIcon != null) {
             mLockIcon.setOnLongClickListener(this::handleLockLongClick);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index 8dd801b..8cc45f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -51,7 +51,7 @@
     private final Context mContext;
     private final NotificationManager mNotificationManager;
     private final Handler mMainHandler;
-    private final List<NotifServiceListener> mNotificationListeners = new ArrayList<>();
+    private final List<NotificationHandler> mNotificationHandlers = new ArrayList<>();
     private final ArrayList<NotificationSettingsListener> mSettingsListeners = new ArrayList<>();
 
     @Inject
@@ -65,11 +65,11 @@
     }
 
     /** Registers a listener that's notified when notifications are added/removed/etc. */
-    public void addNotificationListener(NotifServiceListener listener) {
-        if (mNotificationListeners.contains(listener)) {
+    public void addNotificationHandler(NotificationHandler handler) {
+        if (mNotificationHandlers.contains(handler)) {
             throw new IllegalArgumentException("Listener is already added");
         }
-        mNotificationListeners.add(listener);
+        mNotificationHandlers.add(handler);
     }
 
     /** Registers a listener that's notified when any notification-related settings change. */
@@ -100,7 +100,7 @@
             final RankingMap completeMap = new RankingMap(newRankings.toArray(new Ranking[0]));
 
             for (StatusBarNotification sbn : notifications) {
-                for (NotifServiceListener listener : mNotificationListeners) {
+                for (NotificationHandler listener : mNotificationHandlers) {
                     listener.onNotificationPosted(sbn, completeMap);
                 }
             }
@@ -117,8 +117,8 @@
             mMainHandler.post(() -> {
                 processForRemoteInput(sbn.getNotification(), mContext);
 
-                for (NotifServiceListener listener : mNotificationListeners) {
-                    listener.onNotificationPosted(sbn, rankingMap);
+                for (NotificationHandler handler : mNotificationHandlers) {
+                    handler.onNotificationPosted(sbn, rankingMap);
                 }
             });
         }
@@ -130,8 +130,8 @@
         if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn + " reason: " + reason);
         if (sbn != null && !onPluginNotificationRemoved(sbn, rankingMap)) {
             mMainHandler.post(() -> {
-                for (NotifServiceListener listener : mNotificationListeners) {
-                    listener.onNotificationRemoved(sbn, rankingMap, reason);
+                for (NotificationHandler handler : mNotificationHandlers) {
+                    handler.onNotificationRemoved(sbn, rankingMap, reason);
                 }
             });
         }
@@ -148,8 +148,8 @@
         if (rankingMap != null) {
             RankingMap r = onPluginRankingUpdate(rankingMap);
             mMainHandler.post(() -> {
-                for (NotifServiceListener listener : mNotificationListeners) {
-                    listener.onNotificationRankingUpdate(r);
+                for (NotificationHandler handler : mNotificationHandlers) {
+                    handler.onNotificationRankingUpdate(r);
                 }
             });
         }
@@ -207,7 +207,7 @@
     }
 
     /** Interface for listening to add/remove events that we receive from NotificationManager. */
-    public interface NotifServiceListener {
+    public interface NotificationHandler {
         void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap);
         void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap);
         void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap, int reason);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index 778443c..fdb793e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -33,6 +33,7 @@
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Keeps track of the currently active {@link RemoteInputView}s.
@@ -108,8 +109,8 @@
      * @param token a token identifying the view that is managing the remote input
      */
     public void addRemoteInput(NotificationEntry entry, Object token) {
-        Preconditions.checkNotNull(entry);
-        Preconditions.checkNotNull(token);
+        Objects.requireNonNull(entry);
+        Objects.requireNonNull(token);
 
         boolean found = pruneWeakThenRemoveAndContains(
                 entry /* contains */, null /* remove */, token /* removeToken */);
@@ -129,7 +130,7 @@
      *              entry. If null, the entry is removed regardless.
      */
     public void removeRemoteInput(NotificationEntry entry, Object token) {
-        Preconditions.checkNotNull(entry);
+        Objects.requireNonNull(entry);
 
         pruneWeakThenRemoveAndContains(null /* contains */, entry /* remove */, token);
 
@@ -143,8 +144,8 @@
      * @param token the token of the view managing the remote input.
      */
     public void addSpinning(String key, Object token) {
-        Preconditions.checkNotNull(key);
-        Preconditions.checkNotNull(token);
+        Objects.requireNonNull(key);
+        Objects.requireNonNull(token);
 
         mSpinning.put(key, token);
     }
@@ -158,7 +159,7 @@
      *              entry. If null, the entry is removed regardless.
      */
     public void removeSpinning(String key, Object token) {
-        Preconditions.checkNotNull(key);
+        Objects.requireNonNull(key);
 
         if (token == null || mSpinning.get(key) == token) {
             mSpinning.remove(key);
@@ -237,7 +238,7 @@
 
 
     public void addCallback(Callback callback) {
-        Preconditions.checkNotNull(callback);
+        Objects.requireNonNull(callback);
         mCallbacks.add(callback);
     }
 
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 b8afb78..33d97a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -36,7 +36,7 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.statusbar.NotificationLifetimeExtender;
 import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.NotificationListener.NotifServiceListener;
+import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationRemoveInterceptor;
@@ -179,7 +179,7 @@
 
     /** Once called, the NEM will start processing notification events from system server. */
     public void attach(NotificationListener notificationListener) {
-        notificationListener.addNotificationListener(mNotifListener);
+        notificationListener.addNotificationHandler(mNotifListener);
     }
 
     /** Adds a {@link NotificationEntryListener}. */
@@ -326,7 +326,7 @@
         }
     }
 
-    private final NotifServiceListener mNotifListener = new NotifServiceListener() {
+    private final NotificationHandler mNotifListener = new NotificationHandler() {
         @Override
         public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
             final boolean isUpdate = mActiveNotifications.containsKey(sbn.getKey());
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 7b1dc07..f2765db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
@@ -16,14 +16,14 @@
 
 package com.android.systemui.statusbar.notification;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 
+import java.util.Objects;
+
 /**
  * Root controller for the list of notifications in the shade.
  *
@@ -39,9 +39,9 @@
             NotificationEntryManager entryManager,
             NotificationListContainer listContainer,
             DeviceProvisionedController deviceProvisionedController) {
-        mEntryManager = checkNotNull(entryManager);
-        mListContainer = checkNotNull(listContainer);
-        mDeviceProvisionedController = checkNotNull(deviceProvisionedController);
+        mEntryManager = Objects.requireNonNull(entryManager);
+        mListContainer = Objects.requireNonNull(listContainer);
+        mDeviceProvisionedController = Objects.requireNonNull(deviceProvisionedController);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/CollectionReadyForBuildListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/CollectionReadyForBuildListener.java
index cefb506..87aaea0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/CollectionReadyForBuildListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/CollectionReadyForBuildListener.java
@@ -24,18 +24,6 @@
  */
 public interface CollectionReadyForBuildListener {
     /**
-     * Called after the NotifCollection has received an update from NotificationManager but before
-     * it dispatches any change events to its listeners. This is to inform the list builder that
-     * the first stage of the pipeline has been triggered. After events have been dispatched,
-     * onBuildList() will be called.
-     *
-     * While onBuildList() is always called after this method is called, the converse is not always
-     * true: sometimes the NotifCollection applies an update that does not need to dispatch events,
-     * in which case this method will be skipped and onBuildList will be called directly.
-     */
-    void onBeginDispatchToListeners();
-
-    /**
      * Called by the NotifCollection to indicate that something in the collection has changed and
      * that the list builder should regenerate the list.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index 7f85c88..873cdbc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -35,8 +35,6 @@
 import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
 import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 import android.annotation.IntDef;
 import android.annotation.MainThread;
 import android.annotation.NonNull;
@@ -49,8 +47,9 @@
 import android.util.Log;
 
 import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.NotificationListener.NotifServiceListener;
+import com.android.systemui.statusbar.notification.collection.notifcollection.CoalescedEvent;
+import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer;
+import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer.BatchableNotificationHandler;
 import com.android.systemui.util.Assert;
 
 import java.lang.annotation.Retention;
@@ -60,6 +59,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -109,14 +109,14 @@
     }
 
     /** Initializes the NotifCollection and registers it to receive notification events. */
-    public void attach(NotificationListener listenerService) {
+    public void attach(GroupCoalescer groupCoalescer) {
         Assert.isMainThread();
         if (mAttached) {
             throw new RuntimeException("attach() called twice");
         }
         mAttached = true;
 
-        listenerService.addNotificationListener(mNotifServiceListener);
+        groupCoalescer.setNotificationHandler(mNotifHandler);
     }
 
     /**
@@ -170,7 +170,7 @@
             @CancellationReason int reason,
             @NonNull DismissedByUserStats stats) {
         Assert.isMainThread();
-        checkNotNull(stats);
+        Objects.requireNonNull(stats);
         checkForReentrantCall();
 
         removeNotification(entry.getKey(), null, reason, stats);
@@ -179,15 +179,52 @@
     private void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
         Assert.isMainThread();
 
+        postNotification(sbn, requireRanking(rankingMap, sbn.getKey()), rankingMap);
+        rebuildList();
+    }
+
+    private void onNotificationGroupPosted(List<CoalescedEvent> batch) {
+        Assert.isMainThread();
+
+        Log.d(TAG, "POSTED GROUP " + batch.get(0).getSbn().getGroupKey()
+                + " (" + batch.size() + " events)");
+        for (CoalescedEvent event : batch) {
+            postNotification(event.getSbn(), event.getRanking(), null);
+        }
+        rebuildList();
+    }
+
+    private void onNotificationRemoved(
+            StatusBarNotification sbn,
+            RankingMap rankingMap,
+            int reason) {
+        Assert.isMainThread();
+
+        Log.d(TAG, "REMOVED " + sbn.getKey() + " reason=" + reason);
+        removeNotification(sbn.getKey(), rankingMap, reason, null);
+    }
+
+    private void onNotificationRankingUpdate(RankingMap rankingMap) {
+        Assert.isMainThread();
+        applyRanking(rankingMap);
+        rebuildList();
+    }
+
+    private void postNotification(
+            StatusBarNotification sbn,
+            Ranking ranking,
+            @Nullable RankingMap rankingMap) {
         NotificationEntry entry = mNotificationSet.get(sbn.getKey());
 
         if (entry == null) {
             // A new notification!
             Log.d(TAG, "POSTED  " + sbn.getKey());
 
-            entry = new NotificationEntry(sbn, requireRanking(rankingMap, sbn.getKey()));
+            entry = new NotificationEntry(sbn, ranking);
             mNotificationSet.put(sbn.getKey(), entry);
-            applyRanking(rankingMap);
+            if (rankingMap != null) {
+                applyRanking(rankingMap);
+            }
 
             dispatchOnEntryAdded(entry);
 
@@ -200,34 +237,19 @@
             cancelLifetimeExtension(entry);
 
             entry.setSbn(sbn);
-            applyRanking(rankingMap);
+            if (rankingMap != null) {
+                applyRanking(rankingMap);
+            }
 
             dispatchOnEntryUpdated(entry);
         }
-
-        rebuildList();
-    }
-
-    private void onNotificationRemoved(
-            StatusBarNotification sbn,
-            @Nullable RankingMap rankingMap,
-            int reason) {
-        Assert.isMainThread();
-        Log.d(TAG, "REMOVED " + sbn.getKey() + " reason=" + reason);
-        removeNotification(sbn.getKey(), rankingMap, reason, null);
-    }
-
-    private void onNotificationRankingUpdate(RankingMap rankingMap) {
-        Assert.isMainThread();
-        applyRanking(rankingMap);
-        rebuildList();
     }
 
     private void removeNotification(
             String key,
             @Nullable RankingMap rankingMap,
             @CancellationReason int reason,
-            DismissedByUserStats dismissedByUserStats) {
+            @Nullable DismissedByUserStats dismissedByUserStats) {
 
         NotificationEntry entry = mNotificationSet.get(key);
         if (entry == null) {
@@ -272,7 +294,7 @@
         rebuildList();
     }
 
-    private void applyRanking(RankingMap rankingMap) {
+    private void applyRanking(@NonNull RankingMap rankingMap) {
         for (NotificationEntry entry : mNotificationSet.values()) {
             if (!isLifetimeExtended(entry)) {
                 Ranking ranking = requireRanking(rankingMap, entry.getKey());
@@ -339,9 +361,6 @@
 
     private void dispatchOnEntryAdded(NotificationEntry entry) {
         mAmDispatchingToOtherCode = true;
-        if (mBuildListener != null) {
-            mBuildListener.onBeginDispatchToListeners();
-        }
         for (NotifCollectionListener listener : mNotifCollectionListeners) {
             listener.onEntryAdded(entry);
         }
@@ -350,9 +369,6 @@
 
     private void dispatchOnEntryUpdated(NotificationEntry entry) {
         mAmDispatchingToOtherCode = true;
-        if (mBuildListener != null) {
-            mBuildListener.onBeginDispatchToListeners();
-        }
         for (NotifCollectionListener listener : mNotifCollectionListeners) {
             listener.onEntryUpdated(entry);
         }
@@ -364,22 +380,24 @@
             @CancellationReason int reason,
             boolean removedByUser) {
         mAmDispatchingToOtherCode = true;
-        if (mBuildListener != null) {
-            mBuildListener.onBeginDispatchToListeners();
-        }
         for (NotifCollectionListener listener : mNotifCollectionListeners) {
             listener.onEntryRemoved(entry, reason, removedByUser);
         }
         mAmDispatchingToOtherCode = false;
     }
 
-    private final NotifServiceListener mNotifServiceListener = new NotifServiceListener() {
+    private final BatchableNotificationHandler mNotifHandler = new BatchableNotificationHandler() {
         @Override
         public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
             NotifCollection.this.onNotificationPosted(sbn, rankingMap);
         }
 
         @Override
+        public void onNotificationBatchPosted(List<CoalescedEvent> events) {
+            NotifCollection.this.onNotificationGroupPosted(events);
+        }
+
+        @Override
         public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
             NotifCollection.this.onNotificationRemoved(sbn, rankingMap, REASON_UNKNOWN);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java
index f0a003f..19d90f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java
@@ -18,7 +18,6 @@
 
 import static com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY;
 import static com.android.systemui.statusbar.notification.collection.ListDumper.dumpList;
-import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_BUILD_PENDING;
 import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_BUILD_STARTED;
 import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_FINALIZING;
 import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_GROUPING;
@@ -198,12 +197,6 @@
     private final CollectionReadyForBuildListener mReadyForBuildListener =
             new CollectionReadyForBuildListener() {
                 @Override
-                public void onBeginDispatchToListeners() {
-                    Assert.isMainThread();
-                    mPipelineState.incrementTo(STATE_BUILD_PENDING);
-                }
-
-                @Override
                 public void onBuildList(Collection<NotificationEntry> entries) {
                     Assert.isMainThread();
                     mPipelineState.requireIsBefore(STATE_BUILD_STARTED);
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 dd3a3e0..4f4fb24 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
@@ -29,7 +29,6 @@
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
 
 import android.annotation.NonNull;
@@ -162,9 +161,9 @@
     public NotificationEntry(
             @NonNull StatusBarNotification sbn,
             @NonNull Ranking ranking) {
-        super(checkNotNull(checkNotNull(sbn).getKey()));
+        super(Objects.requireNonNull(Objects.requireNonNull(sbn).getKey()));
 
-        checkNotNull(ranking);
+        Objects.requireNonNull(ranking);
 
         mKey = sbn.getKey();
         setSbn(sbn);
@@ -194,8 +193,8 @@
      * TODO: Make this package-private
      */
     public void setSbn(@NonNull StatusBarNotification sbn) {
-        checkNotNull(sbn);
-        checkNotNull(sbn.getKey());
+        Objects.requireNonNull(sbn);
+        Objects.requireNonNull(sbn.getKey());
 
         if (!sbn.getKey().equals(mKey)) {
             throw new IllegalArgumentException("New key " + sbn.getKey()
@@ -223,8 +222,8 @@
      * TODO: Make this package-private
      */
     public void setRanking(@NonNull Ranking ranking) {
-        checkNotNull(ranking);
-        checkNotNull(ranking.getKey());
+        Objects.requireNonNull(ranking);
+        Objects.requireNonNull(ranking.getKey());
 
         if (!ranking.getKey().equals(mKey)) {
             throw new IllegalArgumentException("New key " + ranking.getKey()
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 8afbc27..6c93618 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
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.notification.collection;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP;
 
@@ -51,6 +50,8 @@
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
+import java.util.Objects;
+
 /** Handles inflating and updating views for notifications. */
 public class NotificationRowBinderImpl implements NotificationRowBinder {
 
@@ -265,7 +266,7 @@
         row.inflateViews();
 
         // bind the click event to the content area
-        checkNotNull(mNotificationClicker).register(row, sbn);
+        Objects.requireNonNull(mNotificationClicker).register(row, sbn);
     }
 
     private void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
index 5fc55da..5e0bd4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
@@ -24,6 +24,7 @@
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
 import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinators;
+import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -36,6 +37,7 @@
  */
 @Singleton
 public class NewNotifPipeline implements Dumpable {
+    private final GroupCoalescer mGroupCoalescer;
     private final NotifCollection mNotifCollection;
     private final NotifListBuilderImpl mNotifPipeline;
     private final NotifCoordinators mNotifPluggableCoordinators;
@@ -45,10 +47,12 @@
 
     @Inject
     public NewNotifPipeline(
+            GroupCoalescer groupCoalescer,
             NotifCollection notifCollection,
             NotifListBuilderImpl notifPipeline,
             NotifCoordinators notifCoordinators,
             DumpController dumpController) {
+        mGroupCoalescer = groupCoalescer;
         mNotifCollection = notifCollection;
         mNotifPipeline = notifPipeline;
         mNotifPluggableCoordinators = notifCoordinators;
@@ -58,20 +62,26 @@
     /** Hooks the new pipeline up to NotificationManager */
     public void initialize(
             NotificationListener notificationService) {
-        mFakePipelineConsumer.attach(mNotifPipeline);
-        mNotifPipeline.attach(mNotifCollection);
-        mNotifCollection.attach(notificationService);
-        mNotifPluggableCoordinators.attach(mNotifCollection, mNotifPipeline);
-
-        Log.d(TAG, "Notif pipeline initialized");
 
         mDumpController.registerDumpable("NotifPipeline", this);
+
+        // Wire up coordinators
+        mFakePipelineConsumer.attach(mNotifPipeline);
+        mNotifPluggableCoordinators.attach(mNotifCollection, mNotifPipeline);
+
+        // Wire up pipeline
+        mNotifPipeline.attach(mNotifCollection);
+        mNotifCollection.attach(mGroupCoalescer);
+        mGroupCoalescer.attach(notificationService);
+
+        Log.d(TAG, "Notif pipeline initialized");
     }
 
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         mFakePipelineConsumer.dump(fd, pw, args);
         mNotifPluggableCoordinators.dump(fd, pw, args);
+        mGroupCoalescer.dump(fd, pw, args);
     }
 
     private static final String TAG = "NewNotifPipeline";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
index 85f828d..084d038 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
@@ -76,19 +76,17 @@
     }
 
     public static final int STATE_IDLE = 0;
-    public static final int STATE_BUILD_PENDING = 1;
-    public static final int STATE_BUILD_STARTED = 2;
-    public static final int STATE_RESETTING = 3;
-    public static final int STATE_PRE_GROUP_FILTERING = 4;
-    public static final int STATE_GROUPING = 5;
-    public static final int STATE_TRANSFORMING = 6;
-    public static final int STATE_SORTING = 7;
-    public static final int STATE_PRE_RENDER_FILTERING = 8;
-    public static final int STATE_FINALIZING = 9;
+    public static final int STATE_BUILD_STARTED = 1;
+    public static final int STATE_RESETTING = 2;
+    public static final int STATE_PRE_GROUP_FILTERING = 3;
+    public static final int STATE_GROUPING = 4;
+    public static final int STATE_TRANSFORMING = 5;
+    public static final int STATE_SORTING = 6;
+    public static final int STATE_PRE_RENDER_FILTERING = 7;
+    public static final int STATE_FINALIZING = 8;
 
     @IntDef(prefix = { "STATE_" }, value = {
             STATE_IDLE,
-            STATE_BUILD_PENDING,
             STATE_BUILD_STARTED,
             STATE_RESETTING,
             STATE_PRE_GROUP_FILTERING,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CoalescedEvent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CoalescedEvent.kt
new file mode 100644
index 0000000..b6218b4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CoalescedEvent.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.notifcollection
+
+import android.service.notification.NotificationListenerService.Ranking
+import android.service.notification.StatusBarNotification
+
+data class CoalescedEvent(
+    val key: String,
+    var position: Int,
+    var sbn: StatusBarNotification,
+    var ranking: Ranking,
+    var batch: EventBatch?
+) {
+    override fun toString(): String {
+        return "CoalescedEvent(key=$key)"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/EventBatch.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/EventBatch.java
new file mode 100644
index 0000000..ac51178
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/EventBatch.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.notifcollection;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a set of notification post events for a particular notification group.
+ */
+public class EventBatch {
+    /** SystemClock.uptimeMillis() */
+    final long mCreatedTimestamp;
+
+    /** SBN.getGroupKey -- same for all members */
+    final String mGroupKey;
+
+    /**
+     * All members of the batch. Must share the same group key. Includes both children and
+     * summaries.
+     */
+    final List<CoalescedEvent> mMembers = new ArrayList<>();
+
+    EventBatch(long createdTimestamp, String groupKey) {
+        mCreatedTimestamp = createdTimestamp;
+        this.mGroupKey = groupKey;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescer.java
new file mode 100644
index 0000000..069c15f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescer.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.notifcollection;
+
+import static com.android.systemui.statusbar.notification.logging.NotifEvent.COALESCED_EVENT;
+import static com.android.systemui.statusbar.notification.logging.NotifEvent.EARLY_BATCH_EMIT;
+import static com.android.systemui.statusbar.notification.logging.NotifEvent.EMIT_EVENT_BATCH;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.MainThread;
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
+import android.service.notification.StatusBarNotification;
+import android.util.ArrayMap;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.Dumpable;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.time.SystemClock;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import javax.inject.Inject;
+
+/**
+ * An attempt to make posting notification groups an atomic process
+ *
+ * Due to the nature of the groups API, individual members of a group are posted to system server
+ * one at a time. This means that whenever a group member is posted, we don't know if there are any
+ * more members soon to be posted.
+ *
+ * The Coalescer sits between the NotificationListenerService and the NotifCollection. It clusters
+ * new notifications that are members of groups and delays their posting until any of the following
+ * criteria are met:
+ *
+ * - A few milliseconds pass (see groupLingerDuration on the constructor)
+ * - Any notification in the delayed group is updated
+ * - Any notification in the delayed group is retracted
+ *
+ * Once we cross this threshold, all members of the group in question are posted atomically to the
+ * NotifCollection. If this process was triggered by an update or removal, then that event is then
+ * passed along to the NotifCollection.
+ */
+@MainThread
+public class GroupCoalescer implements Dumpable {
+    private final DelayableExecutor mMainExecutor;
+    private final SystemClock mClock;
+    private final NotifLog mLog;
+    private final long mGroupLingerDuration;
+
+    private BatchableNotificationHandler mHandler;
+
+    private final Map<String, CoalescedEvent> mCoalescedEvents = new ArrayMap<>();
+    private final Map<String, EventBatch> mBatches = new ArrayMap<>();
+
+    @Inject
+    public GroupCoalescer(
+            @Main DelayableExecutor mainExecutor,
+            SystemClock clock, NotifLog log) {
+        this(mainExecutor, clock, log, GROUP_LINGER_DURATION);
+    }
+
+    /**
+     * @param groupLingerDuration How long, in ms, that notifications that are members of a group
+     *                            are delayed within the GroupCoalescer before being posted
+     */
+    GroupCoalescer(
+            @Main DelayableExecutor mainExecutor,
+            SystemClock clock,
+            NotifLog log,
+            long groupLingerDuration) {
+        mMainExecutor = mainExecutor;
+        mClock = clock;
+        mLog = log;
+        mGroupLingerDuration = groupLingerDuration;
+    }
+
+    /**
+     * Attaches the coalescer to the pipeline, making it ready to receive events. Should only be
+     * called once.
+     */
+    public void attach(NotificationListener listenerService) {
+        listenerService.addNotificationHandler(mListener);
+    }
+
+    public void setNotificationHandler(BatchableNotificationHandler handler) {
+        mHandler = handler;
+    }
+
+    private final NotificationHandler mListener = new NotificationHandler() {
+        @Override
+        public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
+            maybeEmitBatch(sbn.getKey());
+            applyRanking(rankingMap);
+
+            final boolean shouldCoalesce = handleNotificationPosted(sbn, rankingMap);
+
+            if (shouldCoalesce) {
+                mLog.log(COALESCED_EVENT, String.format("Coalesced notification %s", sbn.getKey()));
+                mHandler.onNotificationRankingUpdate(rankingMap);
+            } else {
+                mHandler.onNotificationPosted(sbn, rankingMap);
+            }
+        }
+
+        @Override
+        public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
+            maybeEmitBatch(sbn.getKey());
+            applyRanking(rankingMap);
+            mHandler.onNotificationRemoved(sbn, rankingMap);
+        }
+
+        @Override
+        public void onNotificationRemoved(
+                StatusBarNotification sbn,
+                RankingMap rankingMap,
+                int reason) {
+            maybeEmitBatch(sbn.getKey());
+            applyRanking(rankingMap);
+            mHandler.onNotificationRemoved(sbn, rankingMap, reason);
+        }
+
+        @Override
+        public void onNotificationRankingUpdate(RankingMap rankingMap) {
+            applyRanking(rankingMap);
+            mHandler.onNotificationRankingUpdate(rankingMap);
+        }
+    };
+
+    private void maybeEmitBatch(String memberKey) {
+        CoalescedEvent event = mCoalescedEvents.get(memberKey);
+        if (event != null) {
+            mLog.log(EARLY_BATCH_EMIT,
+                    String.format("Modification of %s triggered early emit of batched group %s",
+                            memberKey, requireNonNull(event.getBatch()).mGroupKey));
+            emitBatch(requireNonNull(event.getBatch()));
+        }
+    }
+
+    /**
+     * @return True if the notification was coalesced and false otherwise.
+     */
+    private boolean handleNotificationPosted(
+            StatusBarNotification sbn,
+            RankingMap rankingMap) {
+
+        if (mCoalescedEvents.containsKey(sbn.getKey())) {
+            throw new IllegalStateException(
+                    "Notification has already been coalesced: " + sbn.getKey());
+        }
+
+        if (sbn.isGroup()) {
+            EventBatch batch = startBatchingGroup(sbn.getGroupKey());
+            CoalescedEvent event =
+                    new CoalescedEvent(
+                            sbn.getKey(),
+                            batch.mMembers.size(),
+                            sbn,
+                            requireRanking(rankingMap, sbn.getKey()),
+                            batch);
+
+            batch.mMembers.add(event);
+
+            mCoalescedEvents.put(event.getKey(), event);
+
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private EventBatch startBatchingGroup(final String groupKey) {
+        EventBatch batch = mBatches.get(groupKey);
+        if (batch == null) {
+            final EventBatch newBatch = new EventBatch(mClock.uptimeMillis(), groupKey);
+            mBatches.put(groupKey, newBatch);
+            mMainExecutor.executeDelayed(() -> emitBatch(newBatch), mGroupLingerDuration);
+
+            batch = newBatch;
+        }
+        return batch;
+    }
+
+    private void emitBatch(EventBatch batch) {
+        if (batch != mBatches.get(batch.mGroupKey)) {
+            // If we emit a batch early, we don't want to emit it a second time when its timeout
+            // expires.
+            return;
+        }
+        if (batch.mMembers.isEmpty()) {
+            throw new IllegalStateException("Batch " + batch.mGroupKey + " cannot be empty");
+        }
+
+        mBatches.remove(batch.mGroupKey);
+
+        final List<CoalescedEvent> events = new ArrayList<>(batch.mMembers);
+        for (CoalescedEvent event : events) {
+            mCoalescedEvents.remove(event.getKey());
+            event.setBatch(null);
+        }
+        events.sort(mEventComparator);
+
+        mLog.log(EMIT_EVENT_BATCH, "Emitting event batch for group " + batch.mGroupKey);
+
+        mHandler.onNotificationBatchPosted(events);
+    }
+
+    private Ranking requireRanking(RankingMap rankingMap, String key) {
+        Ranking ranking = new Ranking();
+        if (!rankingMap.getRanking(key, ranking)) {
+            throw new IllegalArgumentException("Ranking map does not contain key " + key);
+        }
+        return ranking;
+    }
+
+    private void applyRanking(RankingMap rankingMap) {
+        for (CoalescedEvent event : mCoalescedEvents.values()) {
+            Ranking ranking = new Ranking();
+            if (!rankingMap.getRanking(event.getKey(), ranking)) {
+                throw new IllegalStateException(
+                        "Ranking map doesn't contain key: " + event.getKey());
+            }
+            event.setRanking(ranking);
+        }
+    }
+
+    @Override
+    public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+        long now = mClock.uptimeMillis();
+
+        int eventCount = 0;
+
+        pw.println();
+        pw.println("Coalesced notifications:");
+        for (EventBatch batch : mBatches.values()) {
+            pw.println("   Batch " + batch.mGroupKey + ":");
+            pw.println("       Created" + (now - batch.mCreatedTimestamp) + "ms ago");
+            for (CoalescedEvent event : batch.mMembers) {
+                pw.println("       " + event.getKey());
+                eventCount++;
+            }
+        }
+
+        if (eventCount != mCoalescedEvents.size()) {
+            pw.println("    ERROR: batches contain " + mCoalescedEvents.size() + " events but"
+                    + " am tracking " + mCoalescedEvents.size() + " total events");
+            pw.println("    All tracked events:");
+            for (CoalescedEvent event : mCoalescedEvents.values()) {
+                pw.println("        " + event.getKey());
+            }
+        }
+    }
+
+    private final Comparator<CoalescedEvent> mEventComparator = (o1, o2) -> {
+        int cmp = Boolean.compare(
+                o2.getSbn().getNotification().isGroupSummary(),
+                o1.getSbn().getNotification().isGroupSummary());
+        if (cmp == 0) {
+            cmp = o1.getPosition() - o2.getPosition();
+        }
+        return cmp;
+    };
+
+    /**
+     * Extension of {@link NotificationListener.NotificationHandler} to include notification
+     * groups.
+     */
+    public interface BatchableNotificationHandler extends NotificationHandler {
+        /**
+         * Fired whenever the coalescer needs to emit a batch of multiple post events. This is
+         * usually the addition of a new group, but can contain just a single event, or just an
+         * update to a subset of an existing group.
+         */
+        void onNotificationBatchPosted(List<CoalescedEvent> events);
+    }
+
+    private static final int GROUP_LINGER_DURATION = 40;
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
index c18af80..e4a57d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
@@ -23,6 +23,7 @@
 import com.android.systemui.log.RichEvent;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -58,7 +59,10 @@
      */
     @Override
     public String[] getEventLabels() {
-        assert (TOTAL_EVENT_LABELS == (TOTAL_NEM_EVENT_TYPES + TOTAL_LIST_BUILDER_EVENT_TYPES));
+        assert (TOTAL_EVENT_LABELS
+                == (TOTAL_NEM_EVENT_TYPES
+                        + TOTAL_LIST_BUILDER_EVENT_TYPES
+                        + TOTAL_COALESCER_EVENT_TYPES));
         return EVENT_LABELS;
     }
 
@@ -141,7 +145,10 @@
                     "LifetimeExtended",
                     "RemoveIntercepted",
                     "InflationAborted",
-                    "Inflated"
+                    "Inflated",
+
+                    "CoalescedEvent",
+                    "EarlyBatchEmit"
             };
 
     private static final int TOTAL_EVENT_LABELS = EVENT_LABELS.length;
@@ -167,7 +174,7 @@
     /**
      * Events related to {@link NotificationEntryManager}
      */
-    public static final int NOTIF_ADDED = TOTAL_LIST_BUILDER_EVENT_TYPES + 0;
+    public static final int NOTIF_ADDED = TOTAL_LIST_BUILDER_EVENT_TYPES;
     public static final int NOTIF_REMOVED = TOTAL_LIST_BUILDER_EVENT_TYPES + 1;
     public static final int NOTIF_UPDATED = TOTAL_LIST_BUILDER_EVENT_TYPES + 2;
     public static final int FILTER = TOTAL_LIST_BUILDER_EVENT_TYPES + 3;
@@ -180,4 +187,12 @@
     public static final int INFLATION_ABORTED = TOTAL_LIST_BUILDER_EVENT_TYPES + 9;
     public static final int INFLATED = TOTAL_LIST_BUILDER_EVENT_TYPES + 10;
     private static final int TOTAL_NEM_EVENT_TYPES = 11;
+
+    /**
+     * Events related to {@link GroupCoalescer}
+     */
+    public static final int COALESCED_EVENT = TOTAL_NEM_EVENT_TYPES;
+    public static final int EARLY_BATCH_EMIT = TOTAL_NEM_EVENT_TYPES + 1;
+    public static final int EMIT_EVENT_BATCH = TOTAL_NEM_EVENT_TYPES + 2;
+    private static final int TOTAL_COALESCER_EVENT_TYPES = 2;
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
index b444fa5..add982d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar.notification.stack;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 import android.annotation.Nullable;
 import android.content.Context;
 import android.graphics.RectF;
@@ -32,6 +30,8 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 
+import java.util.Objects;
+
 /**
  * Similar in size and appearance to the NotificationShelf, appears at the beginning of some
  * notification sections. Currently only used for gentle notifications.
@@ -51,13 +51,13 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mContents = checkNotNull(findViewById(R.id.content));
+        mContents = Objects.requireNonNull(findViewById(R.id.content));
         bindContents();
     }
 
     private void bindContents() {
-        mLabelView = checkNotNull(findViewById(R.id.header_label));
-        mClearAllButton = checkNotNull(findViewById(R.id.btn_clear_all));
+        mLabelView = Objects.requireNonNull(findViewById(R.id.header_label));
+        mClearAllButton = Objects.requireNonNull(findViewById(R.id.btn_clear_all));
         if (mOnClearClickListener != null) {
             mClearAllButton.setOnClickListener(mOnClearClickListener);
         }
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 199d52f..c74286d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -1299,7 +1299,7 @@
         if (!needsAntiFalsing()) {
             return false;
         }
-        if (mFalsingManager.isClassiferEnabled()) {
+        if (mFalsingManager.isClassifierEnabled()) {
             return mFalsingManager.isFalseTouch();
         }
         return !mQsTouchAboveFalsingThreshold;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 78a5eb2..cd56d06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -710,7 +710,7 @@
         if (!mStatusBar.isFalsingThresholdNeeded()) {
             return false;
         }
-        if (mFalsingManager.isClassiferEnabled()) {
+        if (mFalsingManager.isClassifierEnabled()) {
             return mFalsingManager.isFalseTouch();
         }
         if (!mTouchAboveFalsingThreshold) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index 738d076..cf9d8e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -38,6 +38,11 @@
     void setPowerSaveMode(boolean powerSave);
 
     /**
+     * Returns {@code true} if the device is currently plugged in.
+     */
+    boolean isPluggedIn();
+
+    /**
      * Returns {@code true} if the device is currently in power save mode.
      */
     boolean isPowerSave();
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 f132058..d3e6f53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -193,6 +193,11 @@
     }
 
     @Override
+    public boolean isPluggedIn() {
+        return mPluggedIn;
+    }
+
+    @Override
     public boolean isPowerSave() {
         return mPowerSave;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index b198678..88edf8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -23,11 +23,11 @@
 import android.view.View;
 import android.widget.FrameLayout;
 
-import com.android.internal.util.Preconditions;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.NotificationPanelView;
 import com.android.systemui.statusbar.phone.StatusBarWindowView;
 
+import java.util.Objects;
 import java.util.function.Consumer;
 
 /**
@@ -117,7 +117,7 @@
 
     @Override
     public void addCallback(BrightnessMirrorListener listener) {
-        Preconditions.checkNotNull(listener);
+        Objects.requireNonNull(listener);
         mBrightnessMirrorListeners.add(listener);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 1cb2bd4..0ab08a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -27,7 +27,6 @@
 
 import androidx.annotation.VisibleForTesting;
 
-import com.android.internal.util.Preconditions;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -36,6 +35,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Objects;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -98,7 +98,7 @@
 
     @Override
     public void addCallback(@NonNull Callback callback) {
-        Preconditions.checkNotNull(callback, "Callback must not be null. b/128895449");
+        Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
         if (!mCallbacks.contains(callback)) {
             mCallbacks.add(callback);
         }
@@ -106,7 +106,7 @@
 
     @Override
     public void removeCallback(@NonNull Callback callback) {
-        Preconditions.checkNotNull(callback, "Callback must not be null. b/128895449");
+        Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
         mCallbacks.remove(callback);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/SettableWakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/SettableWakeLock.java
index a797287..37da236 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/SettableWakeLock.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/SettableWakeLock.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.util.wakelock;
 
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
 
 public class SettableWakeLock {
 
@@ -26,7 +26,7 @@
     private boolean mAcquired;
 
     public SettableWakeLock(WakeLock inner, String why) {
-        Preconditions.checkNotNull(inner, "inner wakelock required");
+        Objects.requireNonNull(inner, "inner wakelock required");
 
         mInner = inner;
         mWhy = why;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java
index a19d1df..25efd32 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingManagerProxyTest.java
@@ -21,16 +21,17 @@
 import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.junit.Assert.assertThat;
 
-import android.os.Handler;
 import android.provider.DeviceConfig;
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
+import android.util.DisplayMetrics;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.classifier.brightline.BrightLineFalsingManager;
+import com.android.systemui.dock.DockManager;
+import com.android.systemui.dock.DockManagerFake;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.DeviceConfigProxyFake;
@@ -47,24 +48,22 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
 public class FalsingManagerProxyTest extends SysuiTestCase {
     @Mock(stubOnly = true)
     PluginManager mPluginManager;
     @Mock(stubOnly = true)
     ProximitySensor mProximitySensor;
-    private Handler mHandler;
     private FalsingManagerProxy mProxy;
     private DeviceConfigProxy mDeviceConfig;
-    private TestableLooper mTestableLooper;
+    private DisplayMetrics mDisplayMetrics = new DisplayMetrics();
+    private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
     private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
+    private DockManager mDockManager = new DockManagerFake();
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
         mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
-        mTestableLooper = TestableLooper.get(this);
-        mHandler = new Handler(mTestableLooper.getLooper());
         mDeviceConfig = new DeviceConfigProxyFake();
         mDeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_MANAGER_ENABLED, "false", false);
@@ -79,8 +78,8 @@
 
     @Test
     public void test_brightLineFalsingManagerDisabled() {
-        mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mHandler, mProximitySensor,
-                mDeviceConfig, mUiBgExecutor);
+        mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mExecutor, mDisplayMetrics,
+                mProximitySensor, mDeviceConfig, mDockManager, mUiBgExecutor);
         assertThat(mProxy.getInternalFalsingManager(), instanceOf(FalsingManagerImpl.class));
     }
 
@@ -88,27 +87,27 @@
     public void test_brightLineFalsingManagerEnabled() throws InterruptedException {
         mDeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_MANAGER_ENABLED, "true", false);
-        mTestableLooper.processAllMessages();
-        mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mHandler, mProximitySensor,
-                mDeviceConfig, mUiBgExecutor);
+        mExecutor.runAllReady();
+        mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mExecutor, mDisplayMetrics,
+                mProximitySensor, mDeviceConfig, mDockManager, mUiBgExecutor);
         assertThat(mProxy.getInternalFalsingManager(), instanceOf(BrightLineFalsingManager.class));
     }
 
     @Test
     public void test_brightLineFalsingManagerToggled() throws InterruptedException {
-        mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mHandler, mProximitySensor,
-                mDeviceConfig, mUiBgExecutor);
+        mProxy = new FalsingManagerProxy(getContext(), mPluginManager, mExecutor, mDisplayMetrics,
+                mProximitySensor, mDeviceConfig, mDockManager, mUiBgExecutor);
         assertThat(mProxy.getInternalFalsingManager(), instanceOf(FalsingManagerImpl.class));
 
         mDeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_MANAGER_ENABLED, "true", false);
-        mTestableLooper.processAllMessages();
+        mExecutor.runAllReady();
         assertThat(mProxy.getInternalFalsingManager(),
                 instanceOf(BrightLineFalsingManager.class));
 
         mDeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
                 BRIGHTLINE_FALSING_MANAGER_ENABLED, "false", false);
-        mTestableLooper.processAllMessages();
+        mExecutor.runAllReady();
         assertThat(mProxy.getInternalFalsingManager(), instanceOf(FalsingManagerImpl.class));
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java
index afe4200..e88ff2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DiagonalClassifierTest.java
@@ -24,7 +24,6 @@
 import static org.mockito.Mockito.when;
 
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
 
 import androidx.test.filters.SmallTest;
 
@@ -39,7 +38,6 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
 public class DiagonalClassifierTest extends ClassifierTest {
 
     // Next variable is not actually five, but is very close. 5 degrees is currently the value
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java
index f0f5fc7..44454d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/DistanceClassifierTest.java
@@ -20,7 +20,6 @@
 import static org.junit.Assert.assertThat;
 
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
 
 import androidx.test.filters.SmallTest;
 
@@ -33,7 +32,6 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
 public class DistanceClassifierTest extends ClassifierTest {
 
     private FalsingDataProvider mDataProvider;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/FalsingDataProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/FalsingDataProviderTest.java
index 748c137..448c2f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/FalsingDataProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/FalsingDataProviderTest.java
@@ -21,7 +21,6 @@
 import static org.junit.Assert.assertThat;
 
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
 import android.util.DisplayMetrics;
 import android.view.MotionEvent;
 
@@ -36,7 +35,6 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
 public class FalsingDataProviderTest extends ClassifierTest {
 
     private FalsingDataProvider mDataProvider;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java
index 96b2028..4f8e7c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/PointerCountClassifierTest.java
@@ -22,7 +22,6 @@
 import static org.junit.Assert.assertThat;
 
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
 import android.view.MotionEvent;
 
 import androidx.test.filters.SmallTest;
@@ -34,7 +33,6 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
 public class PointerCountClassifierTest extends ClassifierTest {
 
     private FalsingClassifier mClassifier;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java
index 35d59c1..5b32a394 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ProximityClassifierTest.java
@@ -24,7 +24,6 @@
 import static org.mockito.Mockito.when;
 
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
 import android.view.MotionEvent;
 
 import androidx.test.filters.SmallTest;
@@ -41,7 +40,6 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
 public class ProximityClassifierTest extends ClassifierTest {
 
     private static final long NS_PER_MS = 1000000;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java
index 0355dc3..4346e7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/TypeClassifierTest.java
@@ -30,7 +30,6 @@
 import static org.mockito.Mockito.when;
 
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
 
 import androidx.test.filters.SmallTest;
 
@@ -42,7 +41,6 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
 public class TypeClassifierTest extends ClassifierTest {
 
     @Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
index 387c0da..a8cce00 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/brightline/ZigZagClassifierTest.java
@@ -20,7 +20,6 @@
 import static org.junit.Assert.assertThat;
 
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
 
 import androidx.test.filters.SmallTest;
 
@@ -35,7 +34,6 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
 public class ZigZagClassifierTest extends ClassifierTest {
 
     private FalsingClassifier mClassifier;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 48169ea..0a3bc6d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -154,12 +154,14 @@
 
     @Test
     public void onAlignmentStateChanged_showsSlowChargingIndication() {
-        createController();
-        verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
-        mController.setVisible(true);
+        mInstrumentation.runOnMainSync(() -> {
+            createController();
+            verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
+            mController.setVisible(true);
 
-        mAlignmentListener.getValue().onAlignmentStateChanged(
-                DockManager.ALIGN_STATE_POOR);
+            mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_POOR);
+        });
+        mInstrumentation.waitForIdleSync();
 
         assertThat(mTextView.getText()).isEqualTo(
                 mContext.getResources().getString(R.string.dock_alignment_slow_charging));
@@ -169,11 +171,14 @@
 
     @Test
     public void onAlignmentStateChanged_showsNotChargingIndication() {
-        createController();
-        verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
-        mController.setVisible(true);
+        mInstrumentation.runOnMainSync(() -> {
+            createController();
+            verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
+            mController.setVisible(true);
 
-        mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_TERRIBLE);
+            mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_TERRIBLE);
+        });
+        mInstrumentation.waitForIdleSync();
 
         assertThat(mTextView.getText()).isEqualTo(
                 mContext.getResources().getString(R.string.dock_alignment_not_charging));
@@ -183,13 +188,15 @@
 
     @Test
     public void onAlignmentStateChanged_whileDozing_showsSlowChargingIndication() {
-        createController();
-        verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
-        mController.setVisible(true);
-        mController.setDozing(true);
+        mInstrumentation.runOnMainSync(() -> {
+            createController();
+            verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
+            mController.setVisible(true);
+            mController.setDozing(true);
 
-        mAlignmentListener.getValue().onAlignmentStateChanged(
-                DockManager.ALIGN_STATE_POOR);
+            mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_POOR);
+        });
+        mInstrumentation.waitForIdleSync();
 
         assertThat(mTextView.getText()).isEqualTo(
                 mContext.getResources().getString(R.string.dock_alignment_slow_charging));
@@ -199,12 +206,15 @@
 
     @Test
     public void onAlignmentStateChanged_whileDozing_showsNotChargingIndication() {
-        createController();
-        verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
-        mController.setVisible(true);
-        mController.setDozing(true);
+        mInstrumentation.runOnMainSync(() -> {
+            createController();
+            verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
+            mController.setVisible(true);
+            mController.setDozing(true);
 
-        mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_TERRIBLE);
+            mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_TERRIBLE);
+        });
+        mInstrumentation.waitForIdleSync();
 
         assertThat(mTextView.getText()).isEqualTo(
                 mContext.getResources().getString(R.string.dock_alignment_not_charging));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index d580234..afbe668 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -36,7 +36,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationListener.NotifServiceListener;
+import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -51,7 +51,7 @@
     private static final String TEST_PACKAGE_NAME = "test";
     private static final int TEST_UID = 0;
 
-    @Mock private NotifServiceListener mServiceListener;
+    @Mock private NotificationHandler mNotificationHandler;
     @Mock private NotificationManager mNotificationManager;
 
     private NotificationListener mListener;
@@ -69,21 +69,21 @@
         mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
                 new Notification(), UserHandle.CURRENT, null, 0);
 
-        mListener.addNotificationListener(mServiceListener);
+        mListener.addNotificationHandler(mNotificationHandler);
     }
 
     @Test
     public void testNotificationAddCallsAddNotification() {
         mListener.onNotificationPosted(mSbn, mRanking);
         TestableLooper.get(this).processAllMessages();
-        verify(mServiceListener).onNotificationPosted(mSbn, mRanking);
+        verify(mNotificationHandler).onNotificationPosted(mSbn, mRanking);
     }
 
     @Test
     public void testNotificationRemovalCallsRemoveNotification() {
         mListener.onNotificationRemoved(mSbn, mRanking);
         TestableLooper.get(this).processAllMessages();
-        verify(mServiceListener).onNotificationRemoved(eq(mSbn), eq(mRanking), anyInt());
+        verify(mNotificationHandler).onNotificationRemoved(eq(mSbn), eq(mRanking), anyInt());
     }
 
     @Test
@@ -91,7 +91,7 @@
         mListener.onNotificationRankingUpdate(mRanking);
         TestableLooper.get(this).processAllMessages();
         // RankingMap may be modified by plugins.
-        verify(mServiceListener).onNotificationRankingUpdate(any());
+        verify(mNotificationHandler).onNotificationRankingUpdate(any());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
index 94b3ac4..2605402 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
@@ -116,6 +116,27 @@
 
     public SbnBuilder setNotification(Notification notification) {
         mNotification = notification;
+        mNotificationBuilder = null;
+        return this;
+    }
+
+    public SbnBuilder setContentTitle(Context context, String contentTitle) {
+        modifyNotification(context).setContentTitle(contentTitle);
+        return this;
+    }
+
+    public SbnBuilder setContentText(Context context, String contentText) {
+        modifyNotification(context).setContentText(contentText);
+        return this;
+    }
+
+    public SbnBuilder setGroup(Context context, String groupKey) {
+        modifyNotification(context).setGroup(groupKey);
+        return this;
+    }
+
+    public SbnBuilder setGroupSummary(Context context, boolean isGroupSummary) {
+        modifyNotification(context).setGroupSummary(isGroupSummary);
         return this;
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java
new file mode 100644
index 0000000..c113df0b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection;
+
+import static org.junit.Assert.assertNotNull;
+
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
+import android.service.notification.StatusBarNotification;
+import android.util.ArrayMap;
+
+import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Simulates a NotificationManager
+ *
+ * You can post and retract notifications, each with an accompanying Ranking. The simulator will
+ * keep its RankingMap up to date and call appropriate event listeners.
+ */
+public class NoManSimulator {
+    private final List<NotificationHandler> mListeners = new ArrayList<>();
+    private final Map<String, Ranking> mRankings = new ArrayMap<>();
+
+    public NoManSimulator() {
+    }
+
+    public void addListener(NotificationHandler listener) {
+        mListeners.add(listener);
+    }
+
+    public NotifEvent postNotif(NotificationEntryBuilder builder) {
+        final NotificationEntry entry = builder.build();
+        mRankings.put(entry.getKey(), entry.getRanking());
+        final RankingMap rankingMap = buildRankingMap();
+        for (NotificationHandler listener : mListeners) {
+            listener.onNotificationPosted(entry.getSbn(), rankingMap);
+        }
+        return new NotifEvent(entry.getSbn(), entry.getRanking(), rankingMap);
+    }
+
+    public NotifEvent retractNotif(StatusBarNotification sbn, int reason) {
+        assertNotNull(mRankings.remove(sbn.getKey()));
+        final RankingMap rankingMap = buildRankingMap();
+        for (NotificationHandler listener : mListeners) {
+            listener.onNotificationRemoved(sbn, rankingMap, reason);
+        }
+        return new NotifEvent(sbn, null, rankingMap);
+    }
+
+    public void issueRankingUpdate() {
+        final RankingMap rankingMap = buildRankingMap();
+        for (NotificationHandler listener : mListeners) {
+            listener.onNotificationRankingUpdate(rankingMap);
+        }
+    }
+
+    public void setRanking(String key, Ranking ranking) {
+        mRankings.put(key, ranking);
+    }
+
+    private RankingMap buildRankingMap() {
+        return new RankingMap(mRankings.values().toArray(new Ranking[0]));
+    }
+
+    public static class NotifEvent {
+        public final String key;
+        public final StatusBarNotification sbn;
+        public final Ranking ranking;
+        public final RankingMap rankingMap;
+
+        private NotifEvent(
+                StatusBarNotification sbn,
+                Ranking ranking,
+                RankingMap rankingMap) {
+            this.key = sbn.getKey();
+            this.sbn = sbn;
+            this.ranking = ranking;
+            this.rankingMap = rankingMap;
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index 0dcd253..0837a42 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -19,39 +19,41 @@
 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
 import static android.service.notification.NotificationListenerService.REASON_CLICK;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_UNKNOWN;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import static java.util.Objects.requireNonNull;
+
 import android.annotation.Nullable;
 import android.os.RemoteException;
 import android.service.notification.NotificationListenerService.Ranking;
-import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.NotificationStats;
-import android.service.notification.StatusBarNotification;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.NotificationListener.NotifServiceListener;
 import com.android.systemui.statusbar.RankingBuilder;
+import com.android.systemui.statusbar.notification.collection.NoManSimulator.NotifEvent;
 import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
+import com.android.systemui.statusbar.notification.collection.notifcollection.CoalescedEvent;
+import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer;
+import com.android.systemui.statusbar.notification.collection.notifcollection.GroupCoalescer.BatchableNotificationHandler;
 import com.android.systemui.util.Assert;
 
 import org.junit.Before;
@@ -64,6 +66,8 @@
 import org.mockito.Spy;
 
 import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
 import java.util.Map;
 
 @SmallTest
@@ -72,18 +76,20 @@
 public class NotifCollectionTest extends SysuiTestCase {
 
     @Mock private IStatusBarService mStatusBarService;
-    @Mock private NotificationListener mListenerService;
+    @Mock private GroupCoalescer mGroupCoalescer;
     @Spy private RecordingCollectionListener mCollectionListener;
+    @Mock private CollectionReadyForBuildListener mBuildListener;
 
     @Spy private RecordingLifetimeExtender mExtender1 = new RecordingLifetimeExtender("Extender1");
     @Spy private RecordingLifetimeExtender mExtender2 = new RecordingLifetimeExtender("Extender2");
     @Spy private RecordingLifetimeExtender mExtender3 = new RecordingLifetimeExtender("Extender3");
 
-    @Captor private ArgumentCaptor<NotifServiceListener> mListenerCaptor;
+    @Captor private ArgumentCaptor<BatchableNotificationHandler> mListenerCaptor;
     @Captor private ArgumentCaptor<NotificationEntry> mEntryCaptor;
+    @Captor private ArgumentCaptor<Collection<NotificationEntry>> mBuildListCaptor;
 
     private NotifCollection mCollection;
-    private NotifServiceListener mServiceListener;
+    private BatchableNotificationHandler mNotifHandler;
 
     private NoManSimulator mNoMan;
 
@@ -93,21 +99,23 @@
         Assert.sMainLooper = TestableLooper.get(this).getLooper();
 
         mCollection = new NotifCollection(mStatusBarService);
-        mCollection.attach(mListenerService);
+        mCollection.attach(mGroupCoalescer);
         mCollection.addCollectionListener(mCollectionListener);
+        mCollection.setBuildListener(mBuildListener);
 
         // Capture the listener object that the collection registers with the listener service so
         // we can simulate listener service events in tests below
-        verify(mListenerService).addNotificationListener(mListenerCaptor.capture());
-        mServiceListener = checkNotNull(mListenerCaptor.getValue());
+        verify(mGroupCoalescer).setNotificationHandler(mListenerCaptor.capture());
+        mNotifHandler = requireNonNull(mListenerCaptor.getValue());
 
-        mNoMan = new NoManSimulator(mServiceListener);
+        mNoMan = new NoManSimulator();
+        mNoMan.addListener(mNotifHandler);
     }
 
     @Test
     public void testEventDispatchedWhenNotifPosted() {
         // WHEN a notification is posted
-        PostedNotif notif1 = mNoMan.postNotif(
+        NotifEvent notif1 = mNoMan.postNotif(
                 buildNotif(TEST_PACKAGE, 3)
                         .setRank(4747));
 
@@ -121,13 +129,68 @@
     }
 
     @Test
+    public void testEventDispatchedWhenNotifBatchPosted() {
+        // GIVEN a NotifCollection with one notif already posted
+        mNoMan.postNotif(buildNotif(TEST_PACKAGE, 2)
+                .setGroup(mContext, "group_1")
+                .setContentTitle(mContext, "Old version"));
+
+        clearInvocations(mCollectionListener);
+        clearInvocations(mBuildListener);
+
+        // WHEN three notifications from the same group are posted (one of them an update, two of
+        // them new)
+        NotificationEntry entry1 = buildNotif(TEST_PACKAGE, 1)
+                .setGroup(mContext, "group_1")
+                .build();
+        NotificationEntry entry2 = buildNotif(TEST_PACKAGE, 2)
+                .setGroup(mContext, "group_1")
+                .setContentTitle(mContext, "New version")
+                .build();
+        NotificationEntry entry3 = buildNotif(TEST_PACKAGE, 3)
+                .setGroup(mContext, "group_1")
+                .build();
+
+        mNotifHandler.onNotificationBatchPosted(Arrays.asList(
+                new CoalescedEvent(entry1.getKey(), 0, entry1.getSbn(), entry1.getRanking(), null),
+                new CoalescedEvent(entry2.getKey(), 1, entry2.getSbn(), entry2.getRanking(), null),
+                new CoalescedEvent(entry3.getKey(), 2, entry3.getSbn(), entry3.getRanking(), null)
+        ));
+
+        // THEN onEntryAdded is called on the new ones
+        verify(mCollectionListener, times(2)).onEntryAdded(mEntryCaptor.capture());
+
+        List<NotificationEntry> capturedAdds = mEntryCaptor.getAllValues();
+
+        assertEquals(entry1.getSbn(), capturedAdds.get(0).getSbn());
+        assertEquals(entry1.getRanking(), capturedAdds.get(0).getRanking());
+
+        assertEquals(entry3.getSbn(), capturedAdds.get(1).getSbn());
+        assertEquals(entry3.getRanking(), capturedAdds.get(1).getRanking());
+
+        // THEN onEntryUpdated is called on the middle one
+        verify(mCollectionListener).onEntryUpdated(mEntryCaptor.capture());
+        NotificationEntry capturedUpdate = mEntryCaptor.getValue();
+        assertEquals(entry2.getSbn(), capturedUpdate.getSbn());
+        assertEquals(entry2.getRanking(), capturedUpdate.getRanking());
+
+        // THEN onBuildList is called only once
+        verify(mBuildListener).onBuildList(mBuildListCaptor.capture());
+        assertEquals(new ArraySet<>(Arrays.asList(
+                capturedAdds.get(0),
+                capturedAdds.get(1),
+                capturedUpdate
+        )), new ArraySet<>(mBuildListCaptor.getValue()));
+    }
+
+    @Test
     public void testEventDispatchedWhenNotifUpdated() {
         // GIVEN a collection with one notif
         mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3)
                 .setRank(4747));
 
         // WHEN the notif is reposted
-        PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3)
+        NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3)
                 .setRank(89));
 
         // THEN the listener is notified
@@ -145,7 +208,7 @@
         mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3));
         clearInvocations(mCollectionListener);
 
-        PostedNotif notif = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
+        NotifEvent notif = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
         NotificationEntry entry = mCollectionListener.getEntry(notif.key);
         clearInvocations(mCollectionListener);
 
@@ -161,7 +224,7 @@
     @Test
     public void testRankingsAreUpdatedForOtherNotifs() {
         // GIVEN a collection with one notif
-        PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3)
+        NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3)
                 .setRank(47));
         NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
 
@@ -178,11 +241,11 @@
     @Test
     public void testRankingUpdateIsProperlyIssuedToEveryone() {
         // GIVEN a collection with a couple notifs
-        PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3)
+        NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3)
                 .setRank(3));
-        PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 8)
+        NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 8)
                 .setRank(2));
-        PostedNotif notif3 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 77)
+        NotifEvent notif3 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 77)
                 .setRank(1));
 
         NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
@@ -217,7 +280,7 @@
     @Test
     public void testNotifEntriesAreNotPersistedAcrossRemovalAndReposting() {
         // GIVEN a notification that has been posted
-        PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3));
+        NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3));
         NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
 
         // WHEN the notification is retracted and then reposted
@@ -234,8 +297,8 @@
         // GIVEN a collection with a couple notifications and a lifetime extender
         mCollection.addNotificationLifetimeExtender(mExtender1);
 
-        PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
-        PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88, "barTag"));
+        NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
+        NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88, "barTag"));
         NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
 
         // WHEN a notification is manually dismissed
@@ -267,9 +330,9 @@
     @Test(expected = IllegalStateException.class)
     public void testDismissingNonExistentNotificationThrows() {
         // GIVEN a collection that originally had three notifs, but where one was dismissed
-        PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
-        PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
-        PostedNotif notif3 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 99));
+        NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
+        NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
+        NotifEvent notif3 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 99));
         NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
         mNoMan.retractNotif(notif2.sbn, REASON_UNKNOWN);
 
@@ -292,8 +355,8 @@
         mCollection.addNotificationLifetimeExtender(mExtender2);
         mCollection.addNotificationLifetimeExtender(mExtender3);
 
-        PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
-        PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
+        NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
+        NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
         NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
 
         // WHEN a notification is removed
@@ -320,8 +383,8 @@
         mCollection.addNotificationLifetimeExtender(mExtender2);
         mCollection.addNotificationLifetimeExtender(mExtender3);
 
-        PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
-        PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
+        NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
+        NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
         NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
 
         // GIVEN a notification gets lifetime-extended by one of them
@@ -357,8 +420,8 @@
         mCollection.addNotificationLifetimeExtender(mExtender2);
         mCollection.addNotificationLifetimeExtender(mExtender3);
 
-        PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
-        PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
+        NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
+        NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
         NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
 
         // GIVEN a notification gets lifetime-extended by a couple of them
@@ -392,8 +455,8 @@
         mCollection.addNotificationLifetimeExtender(mExtender2);
         mCollection.addNotificationLifetimeExtender(mExtender3);
 
-        PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
-        PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
+        NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
+        NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
         NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
 
         // GIVEN a notification gets lifetime-extended by a couple of them
@@ -422,8 +485,8 @@
         mExtender1.shouldExtendLifetime = true;
         mExtender2.shouldExtendLifetime = true;
 
-        PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
-        PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
+        NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
+        NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
         NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
 
         // GIVEN a notification gets lifetime-extended by a couple of them
@@ -452,8 +515,8 @@
         mExtender1.shouldExtendLifetime = true;
         mExtender2.shouldExtendLifetime = true;
 
-        PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
-        PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
+        NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
+        NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
         NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
 
         // GIVEN a notification gets lifetime-extended by a couple of them
@@ -481,8 +544,8 @@
         mExtender1.shouldExtendLifetime = true;
         mExtender2.shouldExtendLifetime = true;
 
-        PostedNotif notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
-        PostedNotif notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
+        NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47));
+        NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88));
         NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
 
         // GIVEN a notification gets lifetime-extended by a couple of them
@@ -491,7 +554,7 @@
         clearInvocations(mExtender1, mExtender2, mExtender3);
 
         // WHEN the notification is reposted
-        PostedNotif notif2a = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88)
+        NotifEvent notif2a = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88)
                 .setRank(4747)
                 .setExplanation("Some new explanation"));
 
@@ -512,53 +575,6 @@
                 .setId(id);
     }
 
-    private static class NoManSimulator {
-        private final NotifServiceListener mListener;
-        private final Map<String, Ranking> mRankings = new ArrayMap<>();
-
-        private NoManSimulator(
-                NotifServiceListener listener) {
-            mListener = listener;
-        }
-
-        PostedNotif postNotif(NotificationEntryBuilder builder) {
-            NotificationEntry entry = builder.build();
-            mRankings.put(entry.getKey(), entry.getRanking());
-            mListener.onNotificationPosted(entry.getSbn(), buildRankingMap());
-            return new PostedNotif(entry.getSbn(), entry.getRanking());
-        }
-
-        void retractNotif(StatusBarNotification sbn, int reason) {
-            assertNotNull(mRankings.remove(sbn.getKey()));
-            mListener.onNotificationRemoved(sbn, buildRankingMap(), reason);
-        }
-
-        void issueRankingUpdate() {
-            mListener.onNotificationRankingUpdate(buildRankingMap());
-        }
-
-        void setRanking(String key, Ranking ranking) {
-            mRankings.put(key, ranking);
-        }
-
-        private RankingMap buildRankingMap() {
-            return new RankingMap(mRankings.values().toArray(new Ranking[0]));
-        }
-    }
-
-    private static class PostedNotif {
-        public final String key;
-        public final StatusBarNotification sbn;
-        public final Ranking ranking;
-
-        private PostedNotif(StatusBarNotification sbn,
-                Ranking ranking) {
-            this.key = sbn.getKey();
-            this.sbn = sbn;
-            this.ranking = ranking;
-        }
-    }
-
     private static class RecordingCollectionListener implements NotifCollectionListener {
         private final Map<String, NotificationEntry> mLastSeenEntries = new ArrayMap<>();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java
index 6e9c2c8..3e4068b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar.notification.collection;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.systemui.statusbar.notification.collection.ListDumper.dumpList;
 
 import static org.junit.Assert.assertEquals;
@@ -67,6 +66,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 @SmallTest
@@ -105,7 +105,7 @@
         mListBuilder.attach(mNotifCollection);
 
         Mockito.verify(mNotifCollection).setBuildListener(mBuildListenerCaptor.capture());
-        mReadyForBuildListener = checkNotNull(mBuildListenerCaptor.getValue());
+        mReadyForBuildListener = Objects.requireNonNull(mBuildListenerCaptor.getValue());
     }
 
     @Test
@@ -1021,7 +1021,6 @@
             mPendingSet.clear();
         }
 
-        mReadyForBuildListener.onBeginDispatchToListeners();
         mReadyForBuildListener.onBuildList(mEntrySet);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
index e6a61d6..300ec18 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
@@ -140,6 +140,28 @@
         return this;
     }
 
+    /* Delegated to Notification.Builder (via SbnBuilder) */
+
+    public NotificationEntryBuilder setContentTitle(Context context, String contentTitle) {
+        mSbnBuilder.setContentTitle(context, contentTitle);
+        return this;
+    }
+
+    public NotificationEntryBuilder setContentText(Context context, String contentText) {
+        mSbnBuilder.setContentText(context, contentText);
+        return this;
+    }
+
+    public NotificationEntryBuilder setGroup(Context context, String groupKey) {
+        mSbnBuilder.setGroup(context, groupKey);
+        return this;
+    }
+
+    public NotificationEntryBuilder setGroupSummary(Context context, boolean isGroupSummary) {
+        mSbnBuilder.setGroupSummary(context, isGroupSummary);
+        return this;
+    }
+
     /* Delegated to RankingBuilder */
 
     public NotificationEntryBuilder setRank(int rank) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescerTest.java
new file mode 100644
index 0000000..7ff3240
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/GroupCoalescerTest.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.notifcollection;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
+import android.service.notification.StatusBarNotification;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
+import com.android.systemui.statusbar.RankingBuilder;
+import com.android.systemui.statusbar.notification.collection.NoManSimulator;
+import com.android.systemui.statusbar.notification.collection.NoManSimulator.NotifEvent;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class GroupCoalescerTest extends SysuiTestCase {
+
+    private GroupCoalescer mCoalescer;
+
+    @Mock private NotificationListener mListenerService;
+    @Mock private GroupCoalescer.BatchableNotificationHandler mListener;
+    @Mock private NotifLog mLog;
+
+    @Captor private ArgumentCaptor<NotificationHandler> mListenerCaptor;
+
+    private final NoManSimulator mNoMan = new NoManSimulator();
+    private final FakeSystemClock mClock = new FakeSystemClock();
+    private final FakeExecutor mExecutor = new FakeExecutor(mClock);
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mCoalescer =
+                new GroupCoalescer(
+                        mExecutor,
+                        mClock,
+                        mLog,
+                        LINGER_DURATION);
+        mCoalescer.setNotificationHandler(mListener);
+        mCoalescer.attach(mListenerService);
+
+        verify(mListenerService).addNotificationHandler(mListenerCaptor.capture());
+        NotificationHandler serviceListener = checkNotNull(mListenerCaptor.getValue());
+        mNoMan.addListener(serviceListener);
+    }
+
+    @Test
+    public void testUngroupedNotificationsAreNotCoalesced() {
+        // WHEN a notification that doesn't have a group key is posted
+        NotifEvent notif1 = mNoMan.postNotif(
+                new NotificationEntryBuilder()
+                        .setId(0)
+                        .setPkg(TEST_PACKAGE_A));
+        mClock.advanceTime(LINGER_DURATION);
+
+        // THEN the event is passed through to the handler
+        verify(mListener).onNotificationPosted(notif1.sbn, notif1.rankingMap);
+
+        // Then the event isn't emitted in a batch
+        verify(mListener, never()).onNotificationBatchPosted(anyList());
+    }
+
+    @Test
+    public void testGroupedNotificationsAreCoalesced() {
+        // WHEN a notification that has a group key is posted
+        NotifEvent notif1 = mNoMan.postNotif(
+                new NotificationEntryBuilder()
+                        .setId(0)
+                        .setPkg(TEST_PACKAGE_A)
+                        .setGroup(mContext, GROUP_1));
+
+        // THEN the event is not passed on to the handler
+        verify(mListener, never()).onNotificationPosted(
+                any(StatusBarNotification.class),
+                any(RankingMap.class));
+
+        // Then the event isn't (yet) emitted in a batch
+        verify(mListener, never()).onNotificationBatchPosted(anyList());
+    }
+
+    @Test
+    public void testCoalescedNotificationsStillPassThroughRankingUpdate() {
+        // WHEN a notification that has a group key is posted
+        NotifEvent notif1 = mNoMan.postNotif(
+                new NotificationEntryBuilder()
+                        .setId(0)
+                        .setPkg(TEST_PACKAGE_A)
+                        .setGroup(mContext, GROUP_1));
+
+        // THEN the listener receives a ranking update instead of an add
+        verify(mListener).onNotificationRankingUpdate(notif1.rankingMap);
+    }
+
+    @Test
+    public void testCoalescedNotificationsArePosted() {
+        // GIVEN three notifs are posted that are part of the same group
+        NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(1)
+                .setGroup(mContext, GROUP_1));
+
+        NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(2)
+                .setGroup(mContext, GROUP_1)
+                .setGroupSummary(mContext, true));
+
+        NotifEvent notif3 = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(3)
+                .setGroup(mContext, GROUP_1));
+
+        verify(mListener, never()).onNotificationPosted(
+                any(StatusBarNotification.class),
+                any(RankingMap.class));
+        verify(mListener, never()).onNotificationBatchPosted(anyList());
+
+        // WHEN enough time passes
+        mClock.advanceTime(LINGER_DURATION);
+
+        // THEN the coalesced notifs are applied. The summary is sorted to the front.
+        verify(mListener).onNotificationBatchPosted(Arrays.asList(
+                new CoalescedEvent(notif2.key, 1, notif2.sbn, notif2.ranking, null),
+                new CoalescedEvent(notif1.key, 0, notif1.sbn, notif1.ranking, null),
+                new CoalescedEvent(notif3.key, 2, notif3.sbn, notif3.ranking, null)
+        ));
+    }
+
+    @Test
+    public void testCoalescedEventsThatAreLaterUngroupedAreEmittedImmediatelyAndNotLater() {
+        // GIVEN a few newly posted notifications in the same group
+        NotifEvent notif1a = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(1)
+                .setContentTitle(mContext, "Grouped message")
+                .setGroup(mContext, GROUP_1));
+        NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(2)
+                .setGroup(mContext, GROUP_1));
+        NotifEvent notif3 = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(3)
+                .setGroup(mContext, GROUP_1));
+
+        verify(mListener, never()).onNotificationPosted(
+                any(StatusBarNotification.class),
+                any(RankingMap.class));
+        verify(mListener, never()).onNotificationBatchPosted(anyList());
+
+        // WHEN one of them is updated to no longer be in the group
+        NotifEvent notif1b = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(1)
+                .setContentTitle(mContext, "Oops no longer grouped"));
+
+        // THEN the pre-existing batch is first emitted
+        InOrder inOrder = inOrder(mListener);
+        inOrder.verify(mListener).onNotificationBatchPosted(Arrays.asList(
+                new CoalescedEvent(notif1a.key, 0, notif1a.sbn, notif1a.ranking, null),
+                new CoalescedEvent(notif2.key, 1, notif2.sbn, notif2.ranking, null),
+                new CoalescedEvent(notif3.key, 2, notif3.sbn, notif3.ranking, null)
+        ));
+
+        // THEN the updated notif is emitted
+        inOrder.verify(mListener).onNotificationPosted(notif1b.sbn, notif1b.rankingMap);
+
+        // WHEN the time runs out on the remainder of the group
+        clearInvocations(mListener);
+        mClock.advanceTime(LINGER_DURATION);
+
+        // THEN no lingering batch is applied
+        verify(mListener, never()).onNotificationBatchPosted(anyList());
+    }
+
+    @Test
+    public void testUpdatingCoalescedNotifTriggersBatchEmit() {
+        // GIVEN two grouped, coalesced notifications
+        NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(1)
+                .setGroup(mContext, GROUP_1));
+        NotifEvent notif2a = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(2)
+                .setContentTitle(mContext, "Version 1")
+                .setGroup(mContext, GROUP_1));
+
+        // WHEN one of them gets updated
+        NotifEvent notif2b = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(2)
+                .setContentTitle(mContext, "Version 2")
+                .setGroup(mContext, GROUP_1));
+
+        // THEN first, the coalesced group is emitted
+        verify(mListener).onNotificationBatchPosted(Arrays.asList(
+                new CoalescedEvent(notif1.key, 0, notif1.sbn, notif1.ranking, null),
+                new CoalescedEvent(notif2a.key, 1, notif2a.sbn, notif2a.ranking, null)
+        ));
+        verify(mListener, never()).onNotificationPosted(
+                any(StatusBarNotification.class),
+                any(RankingMap.class));
+
+        // THEN second, the update is emitted
+        mClock.advanceTime(LINGER_DURATION);
+        verify(mListener).onNotificationBatchPosted(Collections.singletonList(
+                new CoalescedEvent(notif2b.key, 0, notif2b.sbn, notif2b.ranking, null)
+        ));
+    }
+
+    @Test
+    public void testRemovingCoalescedNotifTriggersBatchEmit() {
+        // GIVEN two grouped, coalesced notifications
+        NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(1)
+                .setGroup(mContext, GROUP_1));
+        NotifEvent notif2a = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(2)
+                .setGroup(mContext, GROUP_1));
+
+        // WHEN one of them gets retracted
+        NotifEvent notif2b = mNoMan.retractNotif(notif2a.sbn, 0);
+
+        // THEN first, the coalesced group is emitted
+        InOrder inOrder = inOrder(mListener);
+        inOrder.verify(mListener).onNotificationBatchPosted(Arrays.asList(
+                new CoalescedEvent(notif1.key, 0, notif1.sbn, notif1.ranking, null),
+                new CoalescedEvent(notif2a.key, 1, notif2a.sbn, notif2a.ranking, null)
+        ));
+
+        // THEN second, the removal is emitted
+        inOrder.verify(mListener).onNotificationRemoved(notif2b.sbn, notif2b.rankingMap, 0);
+    }
+
+    @Test
+    public void testRankingsAreUpdated() {
+        // GIVEN a couple coalesced notifications
+        NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(1)
+                .setGroup(mContext, GROUP_1));
+        NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(2)
+                .setGroup(mContext, GROUP_1));
+
+        // WHEN an update to an unrelated notification comes in that updates their rankings
+        Ranking ranking1b = new RankingBuilder()
+                .setKey(notif1.key)
+                .setLastAudiblyAlertedMs(4747)
+                .build();
+        Ranking ranking2b = new RankingBuilder()
+                .setKey(notif2.key)
+                .setLastAudiblyAlertedMs(3333)
+                .build();
+        mNoMan.setRanking(notif1.key, ranking1b);
+        mNoMan.setRanking(notif2.key, ranking2b);
+        mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_B)
+                .setId(17));
+
+        // THEN they have the new rankings when they are eventually emitted
+        mClock.advanceTime(LINGER_DURATION);
+        verify(mListener).onNotificationBatchPosted(Arrays.asList(
+                new CoalescedEvent(notif1.key, 0, notif1.sbn, ranking1b, null),
+                new CoalescedEvent(notif2.key, 1, notif2.sbn, ranking2b, null)
+        ));
+    }
+
+    private static final long LINGER_DURATION = 4700;
+
+    private static final String TEST_PACKAGE_A = "com.test.package_a";
+    private static final String TEST_PACKAGE_B = "com.test.package_b";
+    private static final String GROUP_1 = "group_1";
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
index a024454..3d59d61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
@@ -18,8 +18,6 @@
 
 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
@@ -50,6 +48,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Objects;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
@@ -85,11 +85,11 @@
 
         // Capture the entry listener object so we can simulate events in tests below
         verify(mEntryManager).addNotificationEntryListener(mListenerCaptor.capture());
-        mEntryListener = checkNotNull(mListenerCaptor.getValue());
+        mEntryListener = Objects.requireNonNull(mListenerCaptor.getValue());
 
         // Capture the callback object so we can simulate callback events in tests below
         verify(mCommandQueue).addCallback(mCallbacksCaptor.capture());
-        mCallbacks = checkNotNull(mCallbacksCaptor.getValue());
+        mCallbacks = Objects.requireNonNull(mCallbacksCaptor.getValue());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java
index e15ca1d..27b225e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java
@@ -30,14 +30,13 @@
 import android.os.SystemClock;
 import android.util.ArraySet;
 
-import com.android.internal.util.Preconditions;
-
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 import javax.annotation.Nullable;
@@ -113,7 +112,7 @@
 
     @Override
     protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
-        Preconditions.checkNotNull(listener);
+        Objects.requireNonNull(listener);
         for (FakeGenericSensor s : mSensors) {
             if (sensor == null || s.mSensor == sensor) {
                 s.mListeners.remove(listener);
@@ -125,8 +124,8 @@
     protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
             int delayUs,
             Handler handler, int maxReportLatencyUs, int reservedFlags) {
-        Preconditions.checkNotNull(sensor);
-        Preconditions.checkNotNull(listener);
+        Objects.requireNonNull(sensor);
+        Objects.requireNonNull(listener);
         for (FakeGenericSensor s : mSensors) {
             if (s.mSensor == sensor) {
                 s.mListeners.add(listener);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBatteryController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBatteryController.java
index df76f01..8ec4cb8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBatteryController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBatteryController.java
@@ -45,6 +45,11 @@
     }
 
     @Override
+    public boolean isPluggedIn() {
+        return false;
+    }
+
+    @Override
     public boolean isPowerSave() {
         return false;
     }
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiTapAndHold.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiTapAndHold.java
index 6a1f1a5..a0428a5 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiTapAndHold.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiTapAndHold.java
@@ -38,6 +38,12 @@
     }
 
     @Override
+    protected void onUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        super.onUp(event, rawEvent, policyFlags);
+        cancelAfterDoubleTapTimeout(event, rawEvent, policyFlags);
+    }
+
+    @Override
     public String getGestureName() {
         switch (mTargetTaps) {
             case 2:
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index f6eb31b..ba890c5 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -286,10 +286,6 @@
 
     @Override
     public void onDoubleTapAndHold() {
-        // Pointers should not be zero when running this command.
-        if (mState.getLastReceivedEvent().getPointerCount() == 0) {
-            return;
-        }
         // Try to use the standard accessibility API to long click
         if (!mAms.performActionOnAccessibilityFocusedItem(
                 AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK)) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 202f900..bf801fc 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -970,6 +970,8 @@
         } else {
             pw.println(compatPkgs);
         }
+        pw.print(prefix); pw.print("Inline Suggestions Enabled: ");
+        pw.println(isInlineSuggestionsEnabled());
         pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune);
 
         pw.print(prefix); pw.print("Disabled apps: ");
@@ -1120,6 +1122,14 @@
     }
 
     @GuardedBy("mLock")
+    boolean isInlineSuggestionsEnabled() {
+        if (mInfo != null) {
+            return mInfo.isInlineSuggestionsEnabled();
+        }
+        return false;
+    }
+
+    @GuardedBy("mLock")
     @Nullable RemoteAugmentedAutofillService getRemoteAugmentedAutofillServiceLocked() {
         if (mRemoteAugmentedAutofillService == null) {
             final String serviceName = mMaster.mAugmentedAutofillResolver.getServiceName(mUserId);
diff --git a/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java
new file mode 100644
index 0000000..3af15c7
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill;
+
+import static com.android.server.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.service.autofill.Dataset;
+import android.util.Slog;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.autofill.AutofillId;
+import android.view.autofill.IAutoFillManagerClient;
+import android.view.inline.InlinePresentationSpec;
+import android.view.inputmethod.InlineSuggestion;
+import android.view.inputmethod.InlineSuggestionInfo;
+import android.view.inputmethod.InlineSuggestionsRequest;
+import android.view.inputmethod.InlineSuggestionsResponse;
+
+import com.android.internal.view.inline.IInlineContentCallback;
+import com.android.internal.view.inline.IInlineContentProvider;
+import com.android.server.autofill.ui.InlineSuggestionUi;
+
+import java.util.ArrayList;
+
+
+/**
+ * @hide
+ */
+public final class InlineSuggestionFactory {
+    private static final String TAG = "InlineSuggestionFactory";
+
+    /**
+     * Creates an {@link InlineSuggestionsResponse} with the {@code datasets} provided by
+     * augmented autofill service.
+     */
+    public static InlineSuggestionsResponse createAugmentedInlineSuggestionsResponse(
+            int sessionId,
+            @NonNull Dataset[] datasets,
+            @NonNull AutofillId autofillId,
+            @NonNull InlineSuggestionsRequest request,
+            @NonNull Handler uiHandler,
+            @NonNull Context context,
+            @NonNull IAutoFillManagerClient client) {
+        if (sDebug) Slog.d(TAG, "createInlineSuggestionsResponse called");
+
+        final ArrayList<InlineSuggestion> inlineSuggestions = new ArrayList<>();
+        final InlineSuggestionUi inlineSuggestionUi = new InlineSuggestionUi(context);
+        for (Dataset dataset : datasets) {
+            // TODO(b/146453195): use the spec in the dataset.
+            InlinePresentationSpec spec = request.getPresentationSpecs().get(0);
+            if (spec == null) {
+                Slog.w(TAG, "InlinePresentationSpec is not provided in the response data set");
+                continue;
+            }
+            InlineSuggestion inlineSuggestion = createAugmentedInlineSuggestion(sessionId, dataset,
+                    autofillId, spec, uiHandler, inlineSuggestionUi, client);
+            inlineSuggestions.add(inlineSuggestion);
+        }
+        return new InlineSuggestionsResponse(inlineSuggestions);
+    }
+
+    private static InlineSuggestion createAugmentedInlineSuggestion(int sessionId,
+            @NonNull Dataset dataset,
+            @NonNull AutofillId autofillId,
+            @NonNull InlinePresentationSpec spec,
+            @NonNull Handler uiHandler,
+            @NonNull InlineSuggestionUi inlineSuggestionUi,
+            @NonNull IAutoFillManagerClient client) {
+        // TODO(b/146453195): fill in the autofill hint properly.
+        final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo(
+                spec, InlineSuggestionInfo.SOURCE_PLATFORM, new String[]{""});
+        final View.OnClickListener onClickListener = createOnClickListener(sessionId, dataset,
+                client);
+        final InlineSuggestion inlineSuggestion = new InlineSuggestion(inlineSuggestionInfo,
+                createInlineContentProvider(autofillId, dataset, uiHandler, inlineSuggestionUi,
+                        onClickListener));
+        return inlineSuggestion;
+    }
+
+    private static IInlineContentProvider.Stub createInlineContentProvider(
+            @NonNull AutofillId autofillId, @NonNull Dataset dataset, @NonNull Handler uiHandler,
+            @NonNull InlineSuggestionUi inlineSuggestionUi,
+            @Nullable View.OnClickListener onClickListener) {
+        return new IInlineContentProvider.Stub() {
+            @Override
+            public void provideContent(int width, int height,
+                    IInlineContentCallback callback) {
+                uiHandler.post(() -> {
+                    SurfaceControl sc = inlineSuggestionUi.inflate(dataset, autofillId,
+                            width, height, onClickListener);
+                    try {
+                        callback.onContent(sc);
+                    } catch (RemoteException e) {
+                        Slog.w(TAG, "Encounter exception calling back with inline content.");
+                    }
+                });
+            }
+        };
+    }
+
+    private static View.OnClickListener createOnClickListener(int sessionId,
+            @NonNull Dataset dataset,
+            @NonNull IAutoFillManagerClient client) {
+        return v -> {
+            if (sDebug) Slog.d(TAG, "Inline suggestion clicked");
+            try {
+                client.autofill(sessionId, dataset.getFieldIds(), dataset.getFieldValues());
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Encounter exception autofilling the values");
+            }
+        };
+    }
+
+    private InlineSuggestionFactory() {
+    }
+}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index c5011b3..2a7357b 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -46,12 +46,15 @@
 import android.view.autofill.AutofillManager;
 import android.view.autofill.AutofillValue;
 import android.view.autofill.IAutoFillManagerClient;
+import android.view.inputmethod.InlineSuggestionsRequest;
 
 import com.android.internal.infra.AbstractRemoteService;
 import com.android.internal.infra.AndroidFuture;
 import com.android.internal.infra.ServiceConnector;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.view.IInlineSuggestionsResponseCallback;
 
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.TimeUnit;
@@ -137,7 +140,9 @@
      */
     public void onRequestAutofillLocked(int sessionId, @NonNull IAutoFillManagerClient client,
             int taskId, @NonNull ComponentName activityComponent, @NonNull AutofillId focusedId,
-            @Nullable AutofillValue focusedValue) {
+            @Nullable AutofillValue focusedValue,
+            @Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
+            @Nullable IInlineSuggestionsResponseCallback inlineSuggestionsCallback) {
         long requestTime = SystemClock.elapsedRealtime();
         AtomicReference<ICancellationSignal> cancellationRef = new AtomicReference<>();
 
@@ -151,10 +156,13 @@
                     final IBinder realClient = resultData
                             .getBinder(AutofillManager.EXTRA_AUGMENTED_AUTOFILL_CLIENT);
                     service.onFillRequest(sessionId, realClient, taskId, activityComponent,
-                            focusedId, focusedValue, requestTime, new IFillCallback.Stub() {
+                            focusedId, focusedValue, requestTime, inlineSuggestionsRequest,
+                            new IFillCallback.Stub() {
                                 @Override
                                 public void onSuccess(@Nullable Dataset[] inlineSuggestionsData) {
-                                    // TODO(b/146453195): handle non-null inline suggestions data.
+                                    maybeHandleInlineSuggestions(sessionId, inlineSuggestionsData,
+                                            focusedId, inlineSuggestionsRequest,
+                                            inlineSuggestionsCallback, client);
                                     requestAutofill.complete(null);
                                 }
 
@@ -216,6 +224,26 @@
         });
     }
 
+    private void maybeHandleInlineSuggestions(int sessionId,
+            @Nullable Dataset[] inlineSuggestionsData, @NonNull AutofillId focusedId,
+            @Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
+            @Nullable IInlineSuggestionsResponseCallback inlineSuggestionsCallback,
+            @NonNull IAutoFillManagerClient client) {
+        if (inlineSuggestionsRequest == null
+                || ArrayUtils.isEmpty(inlineSuggestionsData)
+                || inlineSuggestionsCallback == null) {
+            return;
+        }
+        try {
+            inlineSuggestionsCallback.onInlineSuggestionsResponse(
+                    InlineSuggestionFactory.createAugmentedInlineSuggestionsResponse(
+                            sessionId, inlineSuggestionsData, focusedId, inlineSuggestionsRequest,
+                            getJobHandler(), mContext, client));
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Exception sending inline suggestions response back to IME.");
+        }
+    }
+
     @Override
     public String toString() {
         return "RemoteAugmentedAutofillService["
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 5af4399..3b51329 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -323,7 +323,7 @@
             mInlineSuggestionsResponseCallbackFuture;
 
     @Nullable
-    private InlineSuggestionsRequestCallback mInlineSuggestionsRequestCallback;
+    private InlineSuggestionsRequestCallbackImpl mInlineSuggestionsRequestCallback;
 
     private static final int INLINE_REQUEST_TIMEOUT_MS = 1000;
 
@@ -424,19 +424,7 @@
                 final ArrayList<FillContext> contexts =
                         mergePreviousSessionLocked(/* forSave= */ false);
 
-                InlineSuggestionsRequest suggestionsRequest = null;
-                if (mSuggestionsRequestFuture != null) {
-                    try {
-                        suggestionsRequest = mSuggestionsRequestFuture.get(
-                                INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
-                    } catch (TimeoutException e) {
-                        Log.w(TAG, "Exception getting inline suggestions request in time: " + e);
-                    } catch (CancellationException e) {
-                        Log.w(TAG, "Inline suggestions request cancelled");
-                    } catch (InterruptedException | ExecutionException e) {
-                        throw new RuntimeException(e);
-                    }
-                }
+                final InlineSuggestionsRequest suggestionsRequest = getInlineSuggestionsRequest();
 
                 request = new FillRequest(requestId, contexts, mClientState, flags,
                         suggestionsRequest);
@@ -624,9 +612,8 @@
     /**
      * Returns whether inline suggestions are enabled for Autofill.
      */
-    // TODO(b/137800469): Implement this
     private boolean isInlineSuggestionsEnabled() {
-        return true;
+        return mService.isInlineSuggestionsEnabled();
     }
 
     /**
@@ -639,7 +626,7 @@
             mInlineSuggestionsResponseCallbackFuture = new CompletableFuture<>();
 
             if (mInlineSuggestionsRequestCallback == null) {
-                mInlineSuggestionsRequestCallback = new InlineSuggestionsRequestCallback(this);
+                mInlineSuggestionsRequestCallback = new InlineSuggestionsRequestCallbackImpl(this);
             }
 
             mInputMethodManagerInternal.onCreateInlineSuggestionsRequest(
@@ -649,18 +636,20 @@
         requestNewFillResponseLocked(viewState, newState, flags);
     }
 
-    private static final class InlineSuggestionsRequestCallback
+    private static final class InlineSuggestionsRequestCallbackImpl
             extends IInlineSuggestionsRequestCallback.Stub {
         private final WeakReference<Session> mSession;
 
-        private InlineSuggestionsRequestCallback(Session session) {
+        private InlineSuggestionsRequestCallbackImpl(Session session) {
             mSession = new WeakReference<>(session);
         }
 
         @Override
         public void onInlineSuggestionsUnsupported() throws RemoteException {
-            Log.i(TAG, "inline suggestions request unsupported, "
-                    + "falling back to regular autofill");
+            if (sDebug) {
+                Log.d(TAG, "inline suggestions request unsupported, "
+                        + "falling back to regular autofill");
+            }
             final Session session = mSession.get();
             if (session != null) {
                 synchronized (session.mLock) {
@@ -673,8 +662,9 @@
         @Override
         public void onInlineSuggestionsRequest(InlineSuggestionsRequest request,
                 IInlineSuggestionsResponseCallback callback) throws RemoteException {
-            Log.i(TAG, "onInlineSuggestionsRequest() received: "
-                    + request);
+            if (sDebug) {
+                Log.d(TAG, "onInlineSuggestionsRequest() received: " + request);
+            }
             final Session session = mSession.get();
             if (session != null) {
                 synchronized (session.mLock) {
@@ -2692,21 +2682,8 @@
      */
     private boolean requestShowInlineSuggestions(List<Slice> inlineSuggestionSlices,
             FillResponse response) {
-        IInlineSuggestionsResponseCallback inlineContentCallback = null;
-        synchronized (mLock) {
-            if (mInlineSuggestionsResponseCallbackFuture != null) {
-                try {
-                    inlineContentCallback = mInlineSuggestionsResponseCallbackFuture.get(
-                            INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
-                } catch (TimeoutException e) {
-                    Log.w(TAG, "Exception getting inline suggestions callback in time: " + e);
-                } catch (CancellationException e) {
-                    Log.w(TAG, "Inline suggestions callback cancelled");
-                } catch (InterruptedException | ExecutionException e) {
-                    throw new RuntimeException(e);
-                }
-            }
-        }
+        final IInlineSuggestionsResponseCallback inlineContentCallback =
+                getInlineSuggestionsResponseCallback();
 
         if (inlineContentCallback == null) {
             Log.w(TAG, "Session input method callback is not set yet");
@@ -3063,9 +3040,12 @@
 
         final AutofillId focusedId = AutofillId.withoutSession(mCurrentViewId);
 
-        // TODO(b/137800469): implement inlined suggestions for augmented autofill
+        final InlineSuggestionsRequest inlineSuggestionsRequest = getInlineSuggestionsRequest();
+        final IInlineSuggestionsResponseCallback inlineSuggestionsResponseCallback =
+                getInlineSuggestionsResponseCallback();
+
         remoteService.onRequestAutofillLocked(id, mClient, taskId, mComponentName, focusedId,
-                currentValue);
+                currentValue, inlineSuggestionsRequest, inlineSuggestionsResponseCallback);
 
         if (mAugmentedAutofillDestroyer == null) {
             mAugmentedAutofillDestroyer = () -> remoteService.onDestroyAutofillWindowsRequest();
@@ -3073,6 +3053,40 @@
         return mAugmentedAutofillDestroyer;
     }
 
+    @Nullable
+    private InlineSuggestionsRequest getInlineSuggestionsRequest() {
+        if (mSuggestionsRequestFuture != null) {
+            try {
+                return mSuggestionsRequestFuture.get(
+                        INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            } catch (TimeoutException e) {
+                Log.w(TAG, "Exception getting inline suggestions request in time: " + e);
+            } catch (CancellationException e) {
+                Log.w(TAG, "Inline suggestions request cancelled");
+            } catch (InterruptedException | ExecutionException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return null;
+    }
+
+    @Nullable
+    private IInlineSuggestionsResponseCallback getInlineSuggestionsResponseCallback() {
+        if (mInlineSuggestionsResponseCallbackFuture != null) {
+            try {
+                return mInlineSuggestionsResponseCallbackFuture.get(
+                        INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            } catch (TimeoutException e) {
+                Log.w(TAG, "Exception getting inline suggestions callback in time: " + e);
+            } catch (CancellationException e) {
+                Log.w(TAG, "Inline suggestions callback cancelled");
+            } catch (InterruptedException | ExecutionException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return null;
+    }
+
     @GuardedBy("mLock")
     private void cancelAugmentedAutofillLocked() {
         final RemoteAugmentedAutofillService remoteService = mService
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index e57b7b3..0511bf2 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -24,8 +24,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
-import android.graphics.Color;
-import android.graphics.PixelFormat;
 import android.graphics.drawable.Drawable;
 import android.metrics.LogMaker;
 import android.os.Bundle;
@@ -40,13 +38,9 @@
 import android.util.Slog;
 import android.view.KeyEvent;
 import android.view.SurfaceControl;
-import android.view.SurfaceControlViewHost;
-import android.view.WindowManager;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
-import android.view.autofill.AutofillValue;
 import android.view.autofill.IAutofillWindowPresenter;
-import android.widget.TextView;
 import android.widget.Toast;
 
 import com.android.internal.logging.MetricsLogger;
@@ -189,8 +183,16 @@
             Slog.w(TAG, "getSuggestionSurfaceForShowing() called with null dataset");
         }
         mHandler.post(() -> {
-            final SurfaceControl suggestionSurface = inflateInlineSuggestion(dataset, response,
-                    autofillId, width, height);
+            final InlineSuggestionUi inlineSuggestionUi = new InlineSuggestionUi(mContext);
+            final SurfaceControl suggestionSurface = inlineSuggestionUi.inflate(dataset,
+                    autofillId, width, height, v -> {
+                        Slog.d(TAG, "Inline suggestion clicked");
+                        hideFillUiUiThread(mCallback, true);
+                        if (mCallback != null) {
+                            final int datasetIndex = response.getDatasets().indexOf(dataset);
+                            mCallback.fill(response.getRequestId(), datasetIndex, dataset);
+                        }
+                    });
 
             try {
                 cb.onContent(suggestionSurface);
@@ -201,51 +203,6 @@
     }
 
     /**
-     * TODO(b/137800469): Fill in javadoc, generate custom templated view for inline suggestions.
-     * TODO: Move to ExtServices.
-     *
-     * @return a {@link SurfaceControl} with the inflated content embedded in it.
-     */
-    private SurfaceControl inflateInlineSuggestion(@NonNull Dataset dataset,
-            @NonNull FillResponse response, AutofillId autofillId, int width, int height) {
-        Slog.i(TAG, "inflate() called");
-        final Context context = mContext;
-        final int index = dataset.getFieldIds().indexOf(autofillId);
-        if (index < 0) {
-            Slog.w(TAG, "inflateInlineSuggestion(): AutofillId=" + autofillId
-                    + " not found in dataset");
-        }
-
-        final AutofillValue datasetValue = dataset.getFieldValues().get(index);
-        //TODO(b/137800469): Pass in inputToken from IME.
-        final SurfaceControlViewHost wvr = new SurfaceControlViewHost(context, context.getDisplay(),
-                (IBinder) null);
-        // TODO(b/134365580): Use the package instead of the SurfaceControl itself
-        // for accessibility support.
-        final SurfaceControl sc = wvr.getSurfacePackage().getSurfaceControl();
-
-        TextView textView = new TextView(context);
-        textView.setText(datasetValue.getTextValue());
-        textView.setBackgroundColor(Color.WHITE);
-        textView.setTextColor(Color.BLACK);
-        textView.setOnClickListener(v -> {
-            Slog.d(TAG, "Inline suggestion clicked");
-            hideFillUiUiThread(mCallback, true);
-            if (mCallback != null) {
-                final int datasetIndex = response.getDatasets().indexOf(dataset);
-                mCallback.fill(response.getRequestId(), datasetIndex, dataset);
-            }
-        });
-
-        WindowManager.LayoutParams lp =
-                new WindowManager.LayoutParams(width, height,
-                        WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.OPAQUE);
-        wvr.addView(textView, lp);
-
-        return sc;
-    }
-
-    /**
      * Shows the fill UI, removing the previous fill UI if the has changed.
      *
      * @param focusedId the currently focused field
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionUi.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionUi.java
new file mode 100644
index 0000000..17cb739
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionUi.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.
+ */
+
+package com.android.server.autofill.ui;
+
+import android.annotation.MainThread;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.os.IBinder;
+import android.service.autofill.Dataset;
+import android.util.Log;
+import android.util.Slog;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
+import android.widget.TextView;
+
+/**
+ * This is a temporary inline suggestion UI inflater which will be replaced by the ExtServices
+ * implementation.
+ *
+ * TODO(b/146453086): remove this class once autofill ext service is implemented.
+ *
+ * @hide
+ */
+public class InlineSuggestionUi {
+
+    private static final String TAG = "InlineSuggestionUi";
+
+    private final Context mContext;
+
+    public InlineSuggestionUi(Context context) {
+        this.mContext = context;
+    }
+
+    /**
+     * Returns a {@link SurfaceControl} with the inflated content embedded in it.
+     */
+    @MainThread
+    @Nullable
+    public SurfaceControl inflate(@NonNull Dataset dataset, @NonNull AutofillId autofillId,
+            int width, int height, @Nullable View.OnClickListener onClickListener) {
+        Log.d(TAG, "Inflating the inline suggestion UI");
+        final int index = dataset.getFieldIds().indexOf(autofillId);
+        if (index < 0) {
+            Slog.w(TAG, "inflateInlineSuggestion(): AutofillId=" + autofillId
+                    + " not found in dataset");
+            return null;
+        }
+        final AutofillValue datasetValue = dataset.getFieldValues().get(index);
+        //TODO(b/137800469): Pass in inputToken from IME.
+        final SurfaceControlViewHost wvr = new SurfaceControlViewHost(mContext,
+                mContext.getDisplay(), (IBinder) null);
+        final SurfaceControl sc = wvr.getSurfacePackage().getSurfaceControl();
+
+        TextView textView = new TextView(mContext);
+        textView.setText(datasetValue.getTextValue());
+        textView.setBackgroundColor(Color.WHITE);
+        textView.setTextColor(Color.BLACK);
+        if (onClickListener != null) {
+            textView.setOnClickListener(onClickListener);
+        }
+
+        WindowManager.LayoutParams lp =
+                new WindowManager.LayoutParams(width, height,
+                        WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSPARENT);
+        wvr.addView(textView, lp);
+        return sc;
+    }
+}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 3651a41..3bce322 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -16,8 +16,6 @@
 
 package com.android.server.backup;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 import static java.util.Collections.emptySet;
 
 import android.Manifest;
@@ -68,6 +66,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -124,7 +123,7 @@
     static BackupManagerService sInstance;
 
     static BackupManagerService getInstance() {
-        return checkNotNull(sInstance);
+        return Objects.requireNonNull(sInstance);
     }
 
     private final Context mContext;
diff --git a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
index 92c2ee4..c9b09e3 100644
--- a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
+++ b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
@@ -21,7 +21,6 @@
 import android.os.SELinux;
 import android.util.Slog;
 
-import com.android.internal.util.Preconditions;
 import com.android.server.backup.fullbackup.AppMetadataBackupWriter;
 import com.android.server.backup.remote.ServiceBackupCallback;
 import com.android.server.backup.utils.FullBackupUtils;
@@ -33,6 +32,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.util.Objects;
 
 /**
  * Used by BackupManagerService to perform adb backup for key-value packages. At the moment this
@@ -87,7 +87,7 @@
                 pkg + BACKUP_KEY_VALUE_NEW_STATE_FILENAME_SUFFIX);
 
         mManifestFile = new File(mDataDir, BACKUP_MANIFEST_FILENAME);
-        mAgentTimeoutParameters = Preconditions.checkNotNull(
+        mAgentTimeoutParameters = Objects.requireNonNull(
                 backupManagerService.getAgentTimeoutParameters(),
                 "Timeout parameters cannot be null");
     }
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 2799f12..064cd06 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -18,7 +18,6 @@
 
 import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.server.backup.BackupManagerService.DEBUG;
 import static com.android.server.backup.BackupManagerService.DEBUG_SCHEDULING;
 import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
@@ -159,6 +158,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Queue;
 import java.util.Random;
 import java.util.Set;
@@ -518,7 +518,7 @@
             File dataDir,
             TransportManager transportManager) {
         mUserId = userId;
-        mContext = checkNotNull(context, "context cannot be null");
+        mContext = Objects.requireNonNull(context, "context cannot be null");
         mPackageManager = context.getPackageManager();
         mPackageManagerBinder = AppGlobals.getPackageManager();
         mActivityManager = ActivityManager.getService();
@@ -528,14 +528,14 @@
         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
 
-        checkNotNull(parent, "parent cannot be null");
+        Objects.requireNonNull(parent, "parent cannot be null");
         mBackupManagerBinder = BackupManagerService.asInterface(parent.asBinder());
 
         mAgentTimeoutParameters = new
                 BackupAgentTimeoutParameters(Handler.getMain(), mContext.getContentResolver());
         mAgentTimeoutParameters.start();
 
-        checkNotNull(userBackupThread, "userBackupThread cannot be null");
+        Objects.requireNonNull(userBackupThread, "userBackupThread cannot be null");
         mBackupHandler = new BackupHandler(this, userBackupThread);
 
         // Set up our bookkeeping
@@ -551,7 +551,7 @@
                 mSetupObserver,
                 mUserId);
 
-        mBaseStateDir = checkNotNull(baseStateDir, "baseStateDir cannot be null");
+        mBaseStateDir = Objects.requireNonNull(baseStateDir, "baseStateDir cannot be null");
         // TODO (b/120424138): Remove once the system user is migrated to use the per-user CE
         // directory. Per-user CE directories are managed by vold.
         if (userId == UserHandle.USER_SYSTEM) {
@@ -563,7 +563,7 @@
 
         // TODO (b/120424138): The system user currently uses the cache which is managed by init.rc
         // Initialization and restorecon is managed by vold for per-user CE directories.
-        mDataDir = checkNotNull(dataDir, "dataDir cannot be null");
+        mDataDir = Objects.requireNonNull(dataDir, "dataDir cannot be null");
         mBackupPasswordManager = new BackupPasswordManager(mContext, mBaseStateDir, mRng);
 
         // Receivers for scheduled backups and transport initialization operations.
@@ -625,7 +625,7 @@
             addPackageParticipantsLocked(null);
         }
 
-        mTransportManager = checkNotNull(transportManager, "transportManager cannot be null");
+        mTransportManager = Objects.requireNonNull(transportManager, "transportManager cannot be null");
         mTransportManager.setOnTransportRegisteredListener(this::onTransportRegistered);
         mRegisterTransportsRequestedTime = SystemClock.elapsedRealtime();
         mBackupHandler.postDelayed(
@@ -3047,9 +3047,9 @@
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BACKUP, "updateTransportAttributes");
 
-        Preconditions.checkNotNull(transportComponent, "transportComponent can't be null");
-        Preconditions.checkNotNull(name, "name can't be null");
-        Preconditions.checkNotNull(
+        Objects.requireNonNull(transportComponent, "transportComponent can't be null");
+        Objects.requireNonNull(name, "name can't be null");
+        Objects.requireNonNull(
                 currentDestinationString, "currentDestinationString can't be null");
         Preconditions.checkArgument(
                 (dataManagementIntent == null) == (dataManagementLabel == null),
diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
index 7ea1892..846c6a2 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
@@ -36,7 +36,6 @@
 import android.os.RemoteException;
 import android.util.Slog;
 
-import com.android.internal.util.Preconditions;
 import com.android.server.AppWidgetBackupBridge;
 import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupRestoreTask;
@@ -47,6 +46,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.util.Objects;
 
 /**
  * Core logic for performing one package's full backup, gathering the tarball from the application
@@ -201,7 +201,7 @@
         mOpToken = opToken;
         mTransportFlags = transportFlags;
         mAgentTimeoutParameters =
-                Preconditions.checkNotNull(
+                Objects.requireNonNull(
                         backupManagerService.getAgentTimeoutParameters(),
                         "Timeout parameters cannot be null");
     }
diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java
index e142537..aaf1f0a 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java
@@ -32,13 +32,13 @@
 import android.util.Slog;
 
 import com.android.internal.backup.IObbBackupService;
-import com.android.internal.util.Preconditions;
 import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.UserBackupManagerService;
 import com.android.server.backup.utils.FullBackupUtils;
 
 import java.io.IOException;
 import java.io.OutputStream;
+import java.util.Objects;
 
 /**
  * Full backup/restore to a file/socket.
@@ -52,7 +52,7 @@
     public FullBackupObbConnection(UserBackupManagerService backupManagerService) {
         this.backupManagerService = backupManagerService;
         mService = null;
-        mAgentTimeoutParameters = Preconditions.checkNotNull(
+        mAgentTimeoutParameters = Objects.requireNonNull(
                 backupManagerService.getAgentTimeoutParameters(),
                 "Timeout parameters cannot be null");
     }
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
index 18c38dc..f7f0138 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
@@ -42,7 +42,6 @@
 import android.util.Slog;
 
 import com.android.internal.backup.IBackupTransport;
-import com.android.internal.util.Preconditions;
 import com.android.server.EventLogTags;
 import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupRestoreTask;
@@ -62,6 +61,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicLong;
@@ -171,7 +171,7 @@
         mUserInitiated = userInitiated;
         mCurrentOpToken = backupManagerService.generateRandomIntegerToken();
         mBackupRunnerOpToken = backupManagerService.generateRandomIntegerToken();
-        mAgentTimeoutParameters = Preconditions.checkNotNull(
+        mAgentTimeoutParameters = Objects.requireNonNull(
                 backupManagerService.getAgentTimeoutParameters(),
                 "Timeout parameters cannot be null");
         mUserId = backupManagerService.getUserId();
diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
index 8c48b84..eb62620 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
@@ -31,8 +31,8 @@
 import android.util.Pair;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.backup.IBackupTransport;
-import com.android.internal.util.Preconditions;
 import com.android.server.EventLogTags;
 import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupRestoreTask;
@@ -58,6 +58,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Asynchronous backup/restore handler thread.
@@ -91,14 +92,16 @@
     private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
     private final HandlerThread mBackupThread;
-    private volatile boolean mIsStopping = false;
+
+    @VisibleForTesting
+    volatile boolean mIsStopping = false;
 
     public BackupHandler(
             UserBackupManagerService backupManagerService, HandlerThread backupThread) {
         super(backupThread.getLooper());
         mBackupThread = backupThread;
         this.backupManagerService = backupManagerService;
-        mAgentTimeoutParameters = Preconditions.checkNotNull(
+        mAgentTimeoutParameters = Objects.requireNonNull(
                 backupManagerService.getAgentTimeoutParameters(),
                 "Timeout parameters cannot be null");
     }
@@ -113,6 +116,24 @@
         sendMessage(obtainMessage(BackupHandler.MSG_STOP));
     }
 
+    @Override
+    public void dispatchMessage(Message message) {
+        try {
+            dispatchMessageInternal(message);
+        } catch (Exception e) {
+            // If the backup service is stopping, we'll suppress all exceptions to avoid crashes
+            // caused by code still running after the current user has become unavailable.
+            if (!mIsStopping) {
+                throw e;
+            }
+        }
+    }
+
+    @VisibleForTesting
+    void dispatchMessageInternal(Message message) {
+        super.dispatchMessage(message);
+    }
+
     public void handleMessage(Message msg) {
         if (msg.what == MSG_STOP) {
             Slog.v(TAG, "Stopping backup handler");
@@ -414,7 +435,7 @@
                             try {
                                 params.observer.onTimeout();
                             } catch (RemoteException e) {
-                            /* don't care if the app has gone away */
+                                /* don't care if the app has gone away */
                             }
                         }
                     } else {
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
index 9492118..bda0e3b 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -310,7 +310,7 @@
         mUserInitiated = userInitiated;
         mNonIncremental = nonIncremental;
         mAgentTimeoutParameters =
-                Preconditions.checkNotNull(
+                Objects.requireNonNull(
                         backupManagerService.getAgentTimeoutParameters(),
                         "Timeout parameters cannot be null");
         mStateDirectory = new File(backupManagerService.getBaseStateDir(), transportDirName);
diff --git a/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java b/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java
index e4890e0..376b618 100644
--- a/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java
+++ b/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java
@@ -21,11 +21,11 @@
 
 import android.util.Slog;
 
-import com.android.internal.util.Preconditions;
 import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupRestoreTask;
 import com.android.server.backup.UserBackupManagerService;
 
+import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -45,7 +45,7 @@
         this.backupManagerService = backupManagerService;
         mLatch = new CountDownLatch(1);
         mCurrentOpToken = currentOpToken;
-        mAgentTimeoutParameters = Preconditions.checkNotNull(
+        mAgentTimeoutParameters = Objects.requireNonNull(
                 backupManagerService.getAgentTimeoutParameters(),
                 "Timeout parameters cannot be null");
     }
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index eba9e4a..82bed3b 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -42,7 +42,6 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
 import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupRestoreTask;
@@ -62,6 +61,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Full restore engine, used by both adb restore and transport-based full restore.
@@ -142,7 +142,7 @@
         mOnlyPackage = onlyPackage;
         mAllowApks = allowApks;
         mBuffer = new byte[32 * 1024];
-        mAgentTimeoutParameters = Preconditions.checkNotNull(
+        mAgentTimeoutParameters = Objects.requireNonNull(
                 backupManagerService.getAgentTimeoutParameters(),
                 "Timeout parameters cannot be null");
         mIsAdbRestore = isAdbRestore;
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index de6a080..16484df9f 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -54,7 +54,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.backup.IBackupTransport;
-import com.android.internal.util.Preconditions;
 import com.android.server.AppWidgetBackupBridge;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
@@ -79,6 +78,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 public class PerformUnifiedRestoreTask implements BackupRestoreTask {
@@ -208,7 +208,7 @@
         mFinished = false;
         mDidLaunch = false;
         mListener = listener;
-        mAgentTimeoutParameters = Preconditions.checkNotNull(
+        mAgentTimeoutParameters = Objects.requireNonNull(
                 backupManagerService.getAgentTimeoutParameters(),
                 "Timeout parameters cannot be null");
 
diff --git a/services/core/java/com/android/server/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java
index 7d5b176..72e170f 100644
--- a/services/core/java/com/android/server/AppStateTracker.java
+++ b/services/core/java/com/android/server/AppStateTracker.java
@@ -63,6 +63,7 @@
 import java.io.PrintWriter;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Class to keep track of the information related to "force app standby", which includes:
@@ -416,12 +417,12 @@
             }
             mStarted = true;
 
-            mIActivityManager = Preconditions.checkNotNull(injectIActivityManager());
-            mActivityManagerInternal = Preconditions.checkNotNull(injectActivityManagerInternal());
-            mAppOpsManager = Preconditions.checkNotNull(injectAppOpsManager());
-            mAppOpsService = Preconditions.checkNotNull(injectIAppOpsService());
-            mPowerManagerInternal = Preconditions.checkNotNull(injectPowerManagerInternal());
-            mAppStandbyInternal = Preconditions.checkNotNull(injectAppStandbyInternal());
+            mIActivityManager = Objects.requireNonNull(injectIActivityManager());
+            mActivityManagerInternal = Objects.requireNonNull(injectActivityManagerInternal());
+            mAppOpsManager = Objects.requireNonNull(injectAppOpsManager());
+            mAppOpsService = Objects.requireNonNull(injectIAppOpsService());
+            mPowerManagerInternal = Objects.requireNonNull(injectPowerManagerInternal());
+            mAppStandbyInternal = Objects.requireNonNull(injectAppStandbyInternal());
 
             mFlagsObserver = new FeatureFlagsObserver();
             mFlagsObserver.register();
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index bb78ace..bd8a361 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -47,8 +47,6 @@
 import static android.system.OsConstants.IPPROTO_TCP;
 import static android.system.OsConstants.IPPROTO_UDP;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.BroadcastOptions;
@@ -904,7 +902,7 @@
          * @see IpConnectivityMetrics.Logger
          */
         public IpConnectivityMetrics.Logger getMetricsLogger() {
-            return checkNotNull(LocalServices.getService(IpConnectivityMetrics.Logger.class),
+            return Objects.requireNonNull(LocalServices.getService(IpConnectivityMetrics.Logger.class),
                     "no IpConnectivityMetrics service");
         }
 
@@ -933,7 +931,7 @@
             IDnsResolver dnsresolver, IpConnectivityLog logger, INetd netd, Dependencies deps) {
         if (DBG) log("ConnectivityService starting up");
 
-        mDeps = checkNotNull(deps, "missing Dependencies");
+        mDeps = Objects.requireNonNull(deps, "missing Dependencies");
         mSystemProperties = mDeps.getSystemProperties();
         mNetIdManager = mDeps.makeNetIdManager();
 
@@ -962,14 +960,14 @@
 
         mLingerDelayMs = mSystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);
 
-        mContext = checkNotNull(context, "missing Context");
-        mNMS = checkNotNull(netManager, "missing INetworkManagementService");
-        mStatsService = checkNotNull(statsService, "missing INetworkStatsService");
-        mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
-        mPolicyManagerInternal = checkNotNull(
+        mContext = Objects.requireNonNull(context, "missing Context");
+        mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService");
+        mStatsService = Objects.requireNonNull(statsService, "missing INetworkStatsService");
+        mPolicyManager = Objects.requireNonNull(policyManager, "missing INetworkPolicyManager");
+        mPolicyManagerInternal = Objects.requireNonNull(
                 LocalServices.getService(NetworkPolicyManagerInternal.class),
                 "missing NetworkPolicyManagerInternal");
-        mDnsResolver = checkNotNull(dnsresolver, "missing IDnsResolver");
+        mDnsResolver = Objects.requireNonNull(dnsresolver, "missing IDnsResolver");
         mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler);
 
         mNetd = netd;
@@ -2025,6 +2023,15 @@
                 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
     }
 
+    private void enforceAirplaneModePermission() {
+        enforceAnyPermissionOf(
+                android.Manifest.permission.NETWORK_AIRPLANE_MODE,
+                android.Manifest.permission.NETWORK_SETTINGS,
+                android.Manifest.permission.NETWORK_SETUP_WIZARD,
+                android.Manifest.permission.NETWORK_STACK,
+                NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
+    }
+
     private boolean checkNetworkStackPermission() {
         return checkAnyPermissionOf(
                 android.Manifest.permission.NETWORK_STACK,
@@ -4736,7 +4743,7 @@
 
     @Override
     public void setAirplaneMode(boolean enable) {
-        enforceNetworkStackSettingsOrSetup();
+        enforceAirplaneModePermission();
         final long ident = Binder.clearCallingIdentity();
         try {
             final ContentResolver cr = mContext.getContentResolver();
@@ -5195,7 +5202,7 @@
     @Override
     public NetworkRequest pendingRequestForNetwork(NetworkCapabilities networkCapabilities,
             PendingIntent operation) {
-        checkNotNull(operation, "PendingIntent cannot be null.");
+        Objects.requireNonNull(operation, "PendingIntent cannot be null.");
         networkCapabilities = new NetworkCapabilities(networkCapabilities);
         enforceNetworkRequestPermissions(networkCapabilities);
         enforceMeteredApnPolicy(networkCapabilities);
@@ -5222,7 +5229,7 @@
 
     @Override
     public void releasePendingNetworkRequest(PendingIntent operation) {
-        checkNotNull(operation, "PendingIntent cannot be null.");
+        Objects.requireNonNull(operation, "PendingIntent cannot be null.");
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT,
                 getCallingUid(), 0, operation));
     }
@@ -5280,7 +5287,7 @@
     @Override
     public void pendingListenForNetwork(NetworkCapabilities networkCapabilities,
             PendingIntent operation) {
-        checkNotNull(operation, "PendingIntent cannot be null.");
+        Objects.requireNonNull(operation, "PendingIntent cannot be null.");
         if (!hasWifiNetworkListenPermission(networkCapabilities)) {
             enforceAccessPermission();
         }
diff --git a/services/core/java/com/android/server/ExplicitHealthCheckController.java b/services/core/java/com/android/server/ExplicitHealthCheckController.java
index f7c4aac..77059d9 100644
--- a/services/core/java/com/android/server/ExplicitHealthCheckController.java
+++ b/services/core/java/com/android/server/ExplicitHealthCheckController.java
@@ -47,6 +47,7 @@
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.function.Consumer;
 
@@ -113,9 +114,9 @@
                 Slog.wtf(TAG, "Resetting health check controller callbacks");
             }
 
-            mPassedConsumer = Preconditions.checkNotNull(passedConsumer);
-            mSupportedConsumer = Preconditions.checkNotNull(supportedConsumer);
-            mNotifySyncRunnable = Preconditions.checkNotNull(notifySyncRunnable);
+            mPassedConsumer = Objects.requireNonNull(passedConsumer);
+            mSupportedConsumer = Objects.requireNonNull(supportedConsumer);
+            mNotifySyncRunnable = Objects.requireNonNull(notifySyncRunnable);
         }
     }
 
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index a629b3f..c987620 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -25,8 +25,6 @@
 import static android.system.OsConstants.IPPROTO_UDP;
 import static android.system.OsConstants.SOCK_DGRAM;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 import android.annotation.NonNull;
 import android.app.AppOpsManager;
 import android.content.Context;
@@ -76,6 +74,7 @@
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * A service to manage multiple clients that want to access the IpSec API. The service is
@@ -566,7 +565,7 @@
         }
 
         void put(int key, RefcountedResource<T> obj) {
-            checkNotNull(obj, "Null resources cannot be added");
+            Objects.requireNonNull(obj, "Null resources cannot be added");
             mArray.put(key, obj);
         }
 
@@ -1101,7 +1100,7 @@
         if (requestedSpi > 0 && requestedSpi < 256) {
             throw new IllegalArgumentException("ESP SPI must not be in the range of 0-255.");
         }
-        checkNotNull(binder, "Null Binder passed to allocateSecurityParameterIndex");
+        Objects.requireNonNull(binder, "Null Binder passed to allocateSecurityParameterIndex");
 
         int callingUid = Binder.getCallingUid();
         UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
@@ -1218,7 +1217,7 @@
             throw new IllegalArgumentException(
                     "Specified port number must be a valid non-reserved UDP port");
         }
-        checkNotNull(binder, "Null Binder passed to openUdpEncapsulationSocket");
+        Objects.requireNonNull(binder, "Null Binder passed to openUdpEncapsulationSocket");
 
         int callingUid = Binder.getCallingUid();
         UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
@@ -1278,8 +1277,8 @@
             String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder,
             String callingPackage) {
         enforceTunnelFeatureAndPermissions(callingPackage);
-        checkNotNull(binder, "Null Binder passed to createTunnelInterface");
-        checkNotNull(underlyingNetwork, "No underlying network was specified");
+        Objects.requireNonNull(binder, "Null Binder passed to createTunnelInterface");
+        Objects.requireNonNull(underlyingNetwork, "No underlying network was specified");
         checkInetAddress(localAddr);
         checkInetAddress(remoteAddr);
 
@@ -1556,7 +1555,7 @@
                     "IPsec Tunnel Mode requires PackageManager.FEATURE_IPSEC_TUNNELS");
         }
 
-        checkNotNull(callingPackage, "Null calling package cannot create IpSec tunnels");
+        Objects.requireNonNull(callingPackage, "Null calling package cannot create IpSec tunnels");
         switch (getAppOpsManager().noteOp(TUNNEL_OP, Binder.getCallingUid(), callingPackage)) {
             case AppOpsManager.MODE_DEFAULT:
                 mContext.enforceCallingOrSelfPermission(
@@ -1625,12 +1624,12 @@
     @Override
     public synchronized IpSecTransformResponse createTransform(
             IpSecConfig c, IBinder binder, String callingPackage) throws RemoteException {
-        checkNotNull(c);
+        Objects.requireNonNull(c);
         if (c.getMode() == IpSecTransform.MODE_TUNNEL) {
             enforceTunnelFeatureAndPermissions(callingPackage);
         }
         checkIpSecConfig(c);
-        checkNotNull(binder, "Null Binder passed to createTransform");
+        Objects.requireNonNull(binder, "Null Binder passed to createTransform");
         final int resourceId = mNextResourceId++;
 
         UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index cad917b..c5f1923 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -23,7 +23,6 @@
 import static android.location.LocationManager.PASSIVE_PROVIDER;
 import static android.os.PowerManager.locationPowerSaveModeToString;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.internal.util.Preconditions.checkState;
 
 import android.Manifest;
@@ -121,6 +120,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -821,7 +821,7 @@
 
         @GuardedBy("mLock")
         public void attachLocked(AbstractLocationProvider provider) {
-            checkNotNull(provider);
+            Objects.requireNonNull(provider);
             checkState(mProvider == null);
 
             if (D) {
@@ -1430,7 +1430,7 @@
     @Override
     public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName,
             String featureId, String listenerIdentifier) {
-        Preconditions.checkNotNull(listenerIdentifier);
+        Objects.requireNonNull(listenerIdentifier);
 
         return mGnssManagerService == null ? false : mGnssManagerService.addGnssBatchingCallback(
                 callback, packageName, featureId, listenerIdentifier);
@@ -2119,7 +2119,7 @@
     public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
             PendingIntent intent, String packageName, String featureId,
             String listenerIdentifier) {
-        Preconditions.checkNotNull(listenerIdentifier);
+        Objects.requireNonNull(listenerIdentifier);
 
         synchronized (mLock) {
             if (request == null) request = DEFAULT_LOCATION_REQUEST;
@@ -2470,7 +2470,7 @@
     @Override
     public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
             String packageName, String featureId, String listenerIdentifier) {
-        Preconditions.checkNotNull(listenerIdentifier);
+        Objects.requireNonNull(listenerIdentifier);
 
         if (request == null) request = DEFAULT_LOCATION_REQUEST;
         int allowedResolutionLevel = getCallerAllowedResolutionLevel();
@@ -2567,7 +2567,7 @@
     @Override
     public boolean addGnssMeasurementsListener(IGnssMeasurementsListener listener,
             String packageName, String featureId, String listenerIdentifier) {
-        Preconditions.checkNotNull(listenerIdentifier);
+        Objects.requireNonNull(listenerIdentifier);
 
         return mGnssManagerService == null ? false
                 : mGnssManagerService.addGnssMeasurementsListener(listener, packageName, featureId,
@@ -2600,7 +2600,7 @@
     @Override
     public boolean addGnssNavigationMessageListener(IGnssNavigationMessageListener listener,
             String packageName, String featureId, String listenerIdentifier) {
-        Preconditions.checkNotNull(listenerIdentifier);
+        Objects.requireNonNull(listenerIdentifier);
 
         return mGnssManagerService == null ? false
                 : mGnssManagerService.addGnssNavigationMessageListener(listener, packageName,
diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java
index ad02aad..eac767f 100644
--- a/services/core/java/com/android/server/NativeDaemonConnector.java
+++ b/services/core/java/com/android/server/NativeDaemonConnector.java
@@ -46,6 +46,7 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.LinkedList;
+import java.util.Objects;
 
 /**
  * Generic connector class for interfacing with a native daemon which uses the
@@ -126,7 +127,7 @@
      */
     public void setWarnIfHeld(Object warnIfHeld) {
         Preconditions.checkState(mWarnIfHeld == null);
-        mWarnIfHeld = Preconditions.checkNotNull(warnIfHeld);
+        mWarnIfHeld = Objects.requireNonNull(warnIfHeld);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 0d496b6..1f73650 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -109,6 +109,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * @hide
@@ -456,7 +457,7 @@
     @Override
     public void registerTetheringStatsProvider(ITetheringStatsProvider provider, String name) {
         NetworkStack.checkNetworkStackPermission(mContext);
-        Preconditions.checkNotNull(provider);
+        Objects.requireNonNull(provider);
         synchronized(mTetheringStatsProviders) {
             mTetheringStatsProviders.put(provider, name);
         }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 22fa8ff4..18ccd01 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -61,6 +61,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.IPackageMoveObserver;
 import android.content.pm.PackageManager;
@@ -74,8 +75,6 @@
 import android.os.Binder;
 import android.os.DropBoxManager;
 import android.os.Environment;
-import android.os.Environment.UserEnvironment;
-import android.os.FileUtils;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -183,6 +182,8 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import javax.crypto.SecretKey;
 import javax.crypto.SecretKeyFactory;
@@ -379,6 +380,14 @@
     @GuardedBy("mAppFuseLock")
     private AppFuseBridge mAppFuseBridge = null;
 
+    /** Matches known application dir paths. The first group contains the generic part of the path,
+     * the second group contains the user id (or null if it's a public volume without users), the
+     * third group contains the package name, and the fourth group the remainder of the path.
+     */
+    public static final Pattern KNOWN_APP_DIR_PATHS = Pattern.compile(
+            "(?i)(^/storage/[^/]+/(?:([0-9]+)/)?Android/(?:data|media|obb|sandbox)/)([^/]+)(/.*)?");
+
+
     private VolumeInfo findVolumeByIdOrThrow(String id) {
         synchronized (mLock) {
             final VolumeInfo vol = mVolumes.get(id);
@@ -2102,7 +2111,7 @@
     public void setVolumeNickname(String fsUuid, String nickname) {
         enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
 
-        Preconditions.checkNotNull(fsUuid);
+        Objects.requireNonNull(fsUuid);
         synchronized (mLock) {
             final VolumeRecord rec = mRecords.get(fsUuid);
             rec.nickname = nickname;
@@ -2115,7 +2124,7 @@
     public void setVolumeUserFlags(String fsUuid, int flags, int mask) {
         enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
 
-        Preconditions.checkNotNull(fsUuid);
+        Objects.requireNonNull(fsUuid);
         synchronized (mLock) {
             final VolumeRecord rec = mRecords.get(fsUuid);
             rec.userFlags = (rec.userFlags & ~mask) | (flags & mask);
@@ -2128,7 +2137,7 @@
     public void forgetVolume(String fsUuid) {
         enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
 
-        Preconditions.checkNotNull(fsUuid);
+        Objects.requireNonNull(fsUuid);
 
         synchronized (mLock) {
             final VolumeRecord rec = mRecords.remove(fsUuid);
@@ -2534,7 +2543,7 @@
 
     @Override
     public String getMountedObbPath(String rawPath) {
-        Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
+        Objects.requireNonNull(rawPath, "rawPath cannot be null");
 
         warnOnNotMounted();
 
@@ -2552,7 +2561,7 @@
 
     @Override
     public boolean isObbMounted(String rawPath) {
-        Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
+        Objects.requireNonNull(rawPath, "rawPath cannot be null");
         synchronized (mObbMounts) {
             return mObbPathToStateMap.containsKey(rawPath);
         }
@@ -2561,10 +2570,10 @@
     @Override
     public void mountObb(String rawPath, String canonicalPath, String key,
             IObbActionListener token, int nonce, ObbInfo obbInfo) {
-        Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
-        Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null");
-        Preconditions.checkNotNull(token, "token cannot be null");
-        Preconditions.checkNotNull(obbInfo, "obbIfno cannot be null");
+        Objects.requireNonNull(rawPath, "rawPath cannot be null");
+        Objects.requireNonNull(canonicalPath, "canonicalPath cannot be null");
+        Objects.requireNonNull(token, "token cannot be null");
+        Objects.requireNonNull(obbInfo, "obbIfno cannot be null");
 
         final int callingUid = Binder.getCallingUid();
         final ObbState obbState = new ObbState(rawPath, canonicalPath,
@@ -2578,7 +2587,7 @@
 
     @Override
     public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) {
-        Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
+        Objects.requireNonNull(rawPath, "rawPath cannot be null");
 
         final ObbState existingState;
         synchronized (mObbMounts) {
@@ -3135,7 +3144,6 @@
     public void mkdirs(String callingPkg, String appPath) {
         final int callingUid = Binder.getCallingUid();
         final int userId = UserHandle.getUserId(callingUid);
-        final UserEnvironment userEnv = new UserEnvironment(userId);
         final String propertyName = "sys.user." + userId + ".ce_available";
 
         // Ignore requests to create directories while storage is locked
@@ -3161,25 +3169,36 @@
             throw new IllegalStateException("Failed to resolve " + appPath + ": " + e);
         }
 
-        // Try translating the app path into a vold path, but require that it
-        // belong to the calling package.
-        if (FileUtils.contains(userEnv.buildExternalStorageAppDataDirs(callingPkg), appFile) ||
-                FileUtils.contains(userEnv.buildExternalStorageAppObbDirs(callingPkg), appFile) ||
-                FileUtils.contains(userEnv.buildExternalStorageAppMediaDirs(callingPkg), appFile)) {
-            appPath = appFile.getAbsolutePath();
-            if (!appPath.endsWith("/")) {
-                appPath = appPath + "/";
+        appPath = appFile.getAbsolutePath();
+        if (!appPath.endsWith("/")) {
+            appPath = appPath + "/";
+        }
+        // Ensure that the path we're asked to create is a known application directory
+        // path.
+        final Matcher matcher = KNOWN_APP_DIR_PATHS.matcher(appPath);
+        if (matcher.matches()) {
+            // And that the package dir matches the calling package
+            if (!matcher.group(3).equals(callingPkg)) {
+                throw new SecurityException("Invalid mkdirs path: " + appFile
+                        + " does not contain calling package " + callingPkg);
             }
-
+            // And that the user id part of the path (if any) matches the calling user id,
+            // or if for a public volume (no user id), the user matches the current user
+            if ((matcher.group(2) != null && !matcher.group(2).equals(Integer.toString(userId)))
+                    || (matcher.group(2) == null && userId != mCurrentUserId)) {
+                throw new SecurityException("Invalid mkdirs path: " + appFile
+                        + " does not match calling user id " + userId);
+            }
             try {
-                mVold.mkdirs(appPath);
-                return;
-            } catch (Exception e) {
+                mVold.setupAppDir(appPath, matcher.group(1), callingUid);
+            } catch (RemoteException e) {
                 throw new IllegalStateException("Failed to prepare " + appPath + ": " + e);
             }
-        }
 
-        throw new SecurityException("Invalid mkdirs path: " + appFile);
+            return;
+        }
+        throw new SecurityException("Invalid mkdirs path: " + appFile
+                + " is not a known app path.");
     }
 
     @Override
@@ -3898,8 +3917,22 @@
 
             // Otherwise we're willing to give out sandboxed or non-sandboxed if
             // they hold the runtime permission
-            final boolean hasLegacy = mIAppOpsService.checkOperation(OP_LEGACY_STORAGE,
+            boolean hasLegacy = mIAppOpsService.checkOperation(OP_LEGACY_STORAGE,
                     uid, packageName) == MODE_ALLOWED;
+
+            // Hack(b/147137425): we have to honor hasRequestedLegacyExternalStorage for a short
+            // while to enable 2 cases.
+            // 1) Apps that want to be in scoped storage in R, but want to opt out in Q devices,
+            // because they want to use raw file paths, would fail until fuse is enabled by default.
+            // 2) Test apps that target current sdk will fail. They would fail even after fuse is
+            // enabled, but we are fixing it with b/142395442. We are not planning to enable
+            // fuse by default until b/142395442 is fixed.
+            if (!hasLegacy && !mIsFuseEnabled) {
+                ApplicationInfo ai = mIPackageManager.getApplicationInfo(packageName,
+                        0, UserHandle.getUserId(uid));
+                hasLegacy = ai.hasRequestedLegacyExternalStorage();
+            }
+
             if (hasLegacy && hasWrite) {
                 return Zygote.MOUNT_EXTERNAL_WRITE;
             } else if (hasLegacy && hasRead) {
diff --git a/services/core/java/com/android/server/SystemServerInitThreadPool.java b/services/core/java/com/android/server/SystemServerInitThreadPool.java
index 5ed94e3..179780d 100644
--- a/services/core/java/com/android/server/SystemServerInitThreadPool.java
+++ b/services/core/java/com/android/server/SystemServerInitThreadPool.java
@@ -28,6 +28,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
@@ -73,7 +74,7 @@
      */
     public static @NonNull Future<?> submit(@NonNull Runnable runnable,
             @NonNull String description) {
-        Preconditions.checkNotNull(description, "description cannot be null");
+        Objects.requireNonNull(description, "description cannot be null");
 
         SystemServerInitThreadPool instance;
         synchronized (LOCK) {
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index d19d2dd..c27b0da 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -16,8 +16,6 @@
 
 package com.android.server;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
@@ -55,6 +53,7 @@
 import java.net.NetworkInterface;
 import java.net.SocketException;
 import java.util.ArrayList;
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /** @hide */
@@ -82,9 +81,9 @@
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
 
-        mContext = checkNotNull(context, "missing Context");
-        mNMS = checkNotNull(netManager, "missing INetworkManagementService");
-        mNetd = checkNotNull(NetdService.getInstance(), "could not get netd instance");
+        mContext = Objects.requireNonNull(context, "missing Context");
+        mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService");
+        mNetd = Objects.requireNonNull(NetdService.getInstance(), "could not get netd instance");
     }
 
     /**
@@ -96,7 +95,7 @@
     private TestNetworkInterface createInterface(boolean isTun, LinkAddress[] linkAddrs) {
         enforceTestNetworkPermissions(mContext);
 
-        checkNotNull(linkAddrs, "missing linkAddrs");
+        Objects.requireNonNull(linkAddrs, "missing linkAddrs");
 
         String ifacePrefix = isTun ? TEST_TUN_PREFIX : TEST_TAP_PREFIX;
         String iface = ifacePrefix + sTestTunIndex.getAndIncrement();
@@ -233,8 +232,8 @@
             int callingUid,
             @NonNull IBinder binder)
             throws RemoteException, SocketException {
-        checkNotNull(looper, "missing Looper");
-        checkNotNull(context, "missing Context");
+        Objects.requireNonNull(looper, "missing Looper");
+        Objects.requireNonNull(context, "missing Context");
         // iface and binder validity checked by caller
 
         // Build network info with special testing type
@@ -267,7 +266,7 @@
         // Find the currently assigned addresses, and add them to LinkProperties
         boolean allowIPv4 = false, allowIPv6 = false;
         NetworkInterface netIntf = NetworkInterface.getByName(iface);
-        checkNotNull(netIntf, "No such network interface found: " + netIntf);
+        Objects.requireNonNull(netIntf, "No such network interface found: " + netIntf);
 
         for (InterfaceAddress intfAddr : netIntf.getInterfaceAddresses()) {
             lp.addLinkAddress(
@@ -305,8 +304,8 @@
             @NonNull IBinder binder) {
         enforceTestNetworkPermissions(mContext);
 
-        checkNotNull(iface, "missing Iface");
-        checkNotNull(binder, "missing IBinder");
+        Objects.requireNonNull(iface, "missing Iface");
+        Objects.requireNonNull(binder, "missing IBinder");
 
         if (!(iface.startsWith(INetd.IPSEC_INTERFACE_PREFIX)
                 || iface.startsWith(TEST_TUN_PREFIX))) {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 5996b7d..a372fca0 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -463,7 +463,7 @@
             Log.v(TAG, "addAccountExplicitly: " + account + ", caller's uid " + callingUid
                     + ", pid " + Binder.getCallingPid());
         }
-        Preconditions.checkNotNull(account, "account cannot be null");
+        Objects.requireNonNull(account, "account cannot be null");
         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format("uid %s cannot explicitly add accounts of type: %s",
                     callingUid, account.type);
@@ -544,7 +544,7 @@
 
     @Override
     public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
-        Preconditions.checkNotNull(account, "account cannot be null");
+        Objects.requireNonNull(account, "account cannot be null");
         int callingUid = Binder.getCallingUid();
         int userId = UserHandle.getCallingUserId();
         if (!isAccountManagedByCaller(account.type, callingUid, userId)
@@ -590,8 +590,8 @@
 
     @Override
     public int getAccountVisibility(Account account, String packageName) {
-        Preconditions.checkNotNull(account, "account cannot be null");
-        Preconditions.checkNotNull(packageName, "packageName cannot be null");
+        Objects.requireNonNull(account, "account cannot be null");
+        Objects.requireNonNull(packageName, "packageName cannot be null");
         int callingUid = Binder.getCallingUid();
         int userId = UserHandle.getCallingUserId();
         if (!isAccountManagedByCaller(account.type, callingUid, userId)
@@ -659,7 +659,7 @@
      */
     private Integer resolveAccountVisibility(Account account, @NonNull String packageName,
             UserAccounts accounts) {
-        Preconditions.checkNotNull(packageName, "packageName cannot be null");
+        Objects.requireNonNull(packageName, "packageName cannot be null");
         int uid = -1;
         try {
             long identityToken = clearCallingIdentity();
@@ -755,8 +755,8 @@
 
     @Override
     public boolean setAccountVisibility(Account account, String packageName, int newVisibility) {
-        Preconditions.checkNotNull(account, "account cannot be null");
-        Preconditions.checkNotNull(packageName, "packageName cannot be null");
+        Objects.requireNonNull(account, "account cannot be null");
+        Objects.requireNonNull(packageName, "packageName cannot be null");
         int callingUid = Binder.getCallingUid();
         int userId = UserHandle.getCallingUserId();
         if (!isAccountManagedByCaller(account.type, callingUid, userId)
@@ -1525,7 +1525,7 @@
                     + ", caller's uid " + Binder.getCallingUid()
                     + ", pid " + Binder.getCallingPid());
         }
-        Preconditions.checkNotNull(account, "account cannot be null");
+        Objects.requireNonNull(account, "account cannot be null");
         int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
@@ -1563,8 +1563,8 @@
                     account, key, callingUid, Binder.getCallingPid());
             Log.v(TAG, msg);
         }
-        Preconditions.checkNotNull(account, "account cannot be null");
-        Preconditions.checkNotNull(key, "key cannot be null");
+        Objects.requireNonNull(account, "account cannot be null");
+        Objects.requireNonNull(key, "key cannot be null");
         int userId = UserHandle.getCallingUserId();
         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
@@ -1715,7 +1715,7 @@
                     callingUid);
             Log.v(TAG, msg);
         }
-        Preconditions.checkNotNull(account, "account cannot be null");
+        Objects.requireNonNull(account, "account cannot be null");
         int userId = UserHandle.getCallingUserId();
         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
@@ -2401,8 +2401,8 @@
     @Override
     public void invalidateAuthToken(String accountType, String authToken) {
         int callerUid = Binder.getCallingUid();
-        Preconditions.checkNotNull(accountType, "accountType cannot be null");
-        Preconditions.checkNotNull(authToken, "authToken cannot be null");
+        Objects.requireNonNull(accountType, "accountType cannot be null");
+        Objects.requireNonNull(authToken, "authToken cannot be null");
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "invalidateAuthToken: accountType " + accountType
                     + ", caller's uid " + callerUid
@@ -2518,8 +2518,8 @@
                     + ", caller's uid " + callingUid
                     + ", pid " + Binder.getCallingPid());
         }
-        Preconditions.checkNotNull(account, "account cannot be null");
-        Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
+        Objects.requireNonNull(account, "account cannot be null");
+        Objects.requireNonNull(authTokenType, "authTokenType cannot be null");
         int userId = UserHandle.getCallingUserId();
         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
@@ -2551,8 +2551,8 @@
                     + ", caller's uid " + callingUid
                     + ", pid " + Binder.getCallingPid());
         }
-        Preconditions.checkNotNull(account, "account cannot be null");
-        Preconditions.checkNotNull(authTokenType, "authTokenType cannot be null");
+        Objects.requireNonNull(account, "account cannot be null");
+        Objects.requireNonNull(authTokenType, "authTokenType cannot be null");
         int userId = UserHandle.getCallingUserId();
         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
@@ -2578,7 +2578,7 @@
                     + ", caller's uid " + callingUid
                     + ", pid " + Binder.getCallingPid());
         }
-        Preconditions.checkNotNull(account, "account cannot be null");
+        Objects.requireNonNull(account, "account cannot be null");
         int userId = UserHandle.getCallingUserId();
         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
@@ -2644,7 +2644,7 @@
                     + ", caller's uid " + callingUid
                     + ", pid " + Binder.getCallingPid());
         }
-        Preconditions.checkNotNull(account, "account cannot be null");
+        Objects.requireNonNull(account, "account cannot be null");
         int userId = UserHandle.getCallingUserId();
         if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
@@ -3946,9 +3946,9 @@
         if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
             throw new SecurityException("Can be called only by system UID");
         }
-        Preconditions.checkNotNull(account, "account cannot be null");
-        Preconditions.checkNotNull(packageName, "packageName cannot be null");
-        Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
+        Objects.requireNonNull(account, "account cannot be null");
+        Objects.requireNonNull(packageName, "packageName cannot be null");
+        Objects.requireNonNull(userHandle, "userHandle cannot be null");
 
         final int userId = userHandle.getIdentifier();
 
@@ -4022,9 +4022,9 @@
             throw new SecurityException("Can be called only by system UID");
         }
 
-        Preconditions.checkNotNull(account, "account cannot be null");
-        Preconditions.checkNotNull(packageName, "packageName cannot be null");
-        Preconditions.checkNotNull(userHandle, "userHandle cannot be null");
+        Objects.requireNonNull(account, "account cannot be null");
+        Objects.requireNonNull(packageName, "packageName cannot be null");
+        Objects.requireNonNull(userHandle, "userHandle cannot be null");
 
         final int userId = userHandle.getIdentifier();
 
diff --git a/services/core/java/com/android/server/accounts/CryptoHelper.java b/services/core/java/com/android/server/accounts/CryptoHelper.java
index 2ade673..863d6b9 100644
--- a/services/core/java/com/android/server/accounts/CryptoHelper.java
+++ b/services/core/java/com/android/server/accounts/CryptoHelper.java
@@ -10,6 +10,7 @@
 
 import java.security.GeneralSecurityException;
 import java.security.NoSuchAlgorithmException;
+import java.util.Objects;
 
 import javax.crypto.Cipher;
 import javax.crypto.KeyGenerator;
@@ -54,7 +55,7 @@
 
     @NonNull
     /* default */ Bundle encryptBundle(@NonNull Bundle bundle) throws GeneralSecurityException {
-        Preconditions.checkNotNull(bundle, "Cannot encrypt null bundle.");
+        Objects.requireNonNull(bundle, "Cannot encrypt null bundle.");
         Parcel parcel = Parcel.obtain();
         bundle.writeToParcel(parcel, 0);
         byte[] clearBytes = parcel.marshall();
@@ -76,7 +77,7 @@
 
     @Nullable
     /* default */ Bundle decryptBundle(@NonNull Bundle bundle) throws GeneralSecurityException {
-        Preconditions.checkNotNull(bundle, "Cannot decrypt null bundle.");
+        Objects.requireNonNull(bundle, "Cannot decrypt null bundle.");
         byte[] iv = bundle.getByteArray(KEY_IV);
         byte[] encryptedBytes = bundle.getByteArray(KEY_CIPHER);
         byte[] mac = bundle.getByteArray(KEY_MAC);
diff --git a/services/core/java/com/android/server/accounts/TokenCache.java b/services/core/java/com/android/server/accounts/TokenCache.java
index 2af2f38..e38cf5f 100644
--- a/services/core/java/com/android/server/accounts/TokenCache.java
+++ b/services/core/java/com/android/server/accounts/TokenCache.java
@@ -193,7 +193,7 @@
             String packageName,
             byte[] sigDigest,
             long expiryMillis) {
-        Preconditions.checkNotNull(account);
+        Objects.requireNonNull(account);
         if (token == null || System.currentTimeMillis() > expiryMillis) {
             return;
         }
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 154d16f..a58bd9b 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -570,7 +570,7 @@
             }
             mAm.mAppOpsService.startOperation(AppOpsManager.getToken(mAm.mAppOpsService),
                     AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null,
-                    true);
+                    true, false, null);
         }
 
         final ServiceMap smap = getServiceMapLocked(r.userId);
@@ -1395,7 +1395,7 @@
                         mAm.mAppOpsService.startOperation(
                                 AppOpsManager.getToken(mAm.mAppOpsService),
                                 AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName,
-                                null, true);
+                                null, true, false, "");
                         StatsLog.write(StatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
                                 r.appInfo.uid, r.shortInstanceName,
                                 StatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d7a46fe..dd1f370 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -324,6 +324,7 @@
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.MemInfoReader;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.HexFunction;
 import com.android.internal.util.function.QuadFunction;
 import com.android.internal.util.function.TriFunction;
 import com.android.server.AlarmManagerInternal;
@@ -3120,7 +3121,7 @@
 
     private boolean hasUsageStatsPermission(String callingPackage) {
         final int mode = mAppOpsService.noteOperation(AppOpsManager.OP_GET_USAGE_STATS,
-                Binder.getCallingUid(), callingPackage, null);
+                Binder.getCallingUid(), callingPackage, null, false, "");
         if (mode == AppOpsManager.MODE_DEFAULT) {
             return checkCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS)
                     == PackageManager.PERMISSION_GRANTED;
@@ -5816,7 +5817,8 @@
         public int noteOp(String op, int uid, String packageName) {
             // TODO moltmann: Allow to specify featureId
             return mActivityManagerService.mAppOpsService
-                    .noteOperation(AppOpsManager.strOpToOp(op), uid, packageName, null);
+                    .noteOperation(AppOpsManager.strOpToOp(op), uid, packageName, null,
+                            false, "");
         }
 
         @Override
@@ -5968,7 +5970,7 @@
         }
         // ...and legacy apps get an AppOp check
         int appop = mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
-                uid, packageName, null);
+                uid, packageName, null, false, "");
         if (DEBUG_BACKGROUND_CHECK) {
             Slog.i(TAG, "Legacy app " + uid + "/" + packageName + " bg appop " + appop);
         }
@@ -19253,18 +19255,22 @@
 
         @Override
         public int noteOperation(int code, int uid, @Nullable String packageName,
-                @Nullable String featureId,
-                @NonNull QuadFunction<Integer, Integer, String, String, Integer> superImpl) {
+                @Nullable String featureId, boolean shouldCollectAsyncNotedOp,
+                @Nullable String message,
+                @NonNull HexFunction<Integer, Integer, String, String, Boolean, String, Integer>
+                        superImpl) {
             if (uid == mTargetUid && isTargetOp(code)) {
                 final long identity = Binder.clearCallingIdentity();
                 try {
                     return mAppOpsService.noteProxyOperation(code, Process.SHELL_UID,
-                            "com.android.shell", null, uid, packageName, featureId);
+                            "com.android.shell", null, uid, packageName, featureId,
+                            shouldCollectAsyncNotedOp, message);
                 } finally {
                     Binder.restoreCallingIdentity(identity);
                 }
             }
-            return superImpl.apply(code, uid, packageName, featureId);
+            return superImpl.apply(code, uid, packageName, featureId, shouldCollectAsyncNotedOp,
+                    message);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 79fe610..a4c44fa 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -111,6 +111,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -1785,7 +1786,7 @@
     }
 
     int runGetCurrentUser(PrintWriter pw) throws RemoteException {
-        UserInfo currentUser = Preconditions.checkNotNull(mInterface.getCurrentUser(),
+        UserInfo currentUser = Objects.requireNonNull(mInterface.getCurrentUser(),
                 "Current user not set");
         pw.println(currentUser.id);
         return 0;
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 10492a7..6fca3f6 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -650,7 +650,7 @@
                 // TODO moltmann: Set featureId from caller
                 if (opCode != AppOpsManager.OP_NONE
                         && mService.mAppOpsService.noteOperation(opCode, r.callingUid,
-                                r.callerPackage, null) != AppOpsManager.MODE_ALLOWED) {
+                        r.callerPackage, null, false, "") != AppOpsManager.MODE_ALLOWED) {
                     Slog.w(TAG, "Appop Denial: broadcasting "
                             + r.intent.toString()
                             + " from " + r.callerPackage + " (pid="
@@ -680,10 +680,10 @@
                     break;
                 }
                 int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
-                // TODO moltmann: Set componentId from caller
+                // TODO moltmann: Set featureId from caller
                 if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
                         && mService.mAppOpsService.noteOperation(appOp,
-                        filter.receiverList.uid, filter.packageName, null)
+                        filter.receiverList.uid, filter.packageName, null, false, "")
                         != AppOpsManager.MODE_ALLOWED) {
                     Slog.w(TAG, "Appop Denial: receiving "
                             + r.intent.toString()
@@ -713,10 +713,10 @@
                 skip = true;
             }
         }
-        // TODO moltmann: Set componentId from caller
+        // TODO moltmann: Set featureId from caller
         if (!skip && r.appOp != AppOpsManager.OP_NONE
                 && mService.mAppOpsService.noteOperation(r.appOp,
-                filter.receiverList.uid, filter.packageName, null)
+                filter.receiverList.uid, filter.packageName, null, false, "")
                 != AppOpsManager.MODE_ALLOWED) {
             Slog.w(TAG, "Appop Denial: receiving "
                     + r.intent.toString()
@@ -1370,10 +1370,10 @@
             skip = true;
         } else if (!skip && info.activityInfo.permission != null) {
             final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission);
-            // TODO moltmann: Set componentId from caller
+            // TODO moltmann: Set featureId from caller
             if (opCode != AppOpsManager.OP_NONE
-                    && mService.mAppOpsService.noteOperation(opCode, r.callingUid,
-                            r.callerPackage, null) != AppOpsManager.MODE_ALLOWED) {
+                    && mService.mAppOpsService.noteOperation(opCode, r.callingUid, r.callerPackage,
+                    null, false, "") != AppOpsManager.MODE_ALLOWED) {
                 Slog.w(TAG, "Appop Denial: broadcasting "
                         + r.intent.toString()
                         + " from " + r.callerPackage + " (pid="
@@ -1409,10 +1409,11 @@
                     break;
                 }
                 int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
-                // TODO moltmann: Set componentId from caller
+                // TODO moltmann: Set featureId from caller
                 if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
                         && mService.mAppOpsService.noteOperation(appOp,
-                        info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, null)
+                        info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, null,
+                        false, "")
                         != AppOpsManager.MODE_ALLOWED) {
                     Slog.w(TAG, "Appop Denial: receiving "
                             + r.intent + " to "
@@ -1426,10 +1427,11 @@
                 }
             }
         }
-        // TODO moltmann: Set componentId from caller
+        // TODO moltmann: Set featureId from caller
         if (!skip && r.appOp != AppOpsManager.OP_NONE
                 && mService.mAppOpsService.noteOperation(r.appOp,
-                info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, null)
+                info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, null, false,
+                "")
                 != AppOpsManager.MODE_ALLOWED) {
             Slog.w(TAG, "Appop Denial: receiving "
                     + r.intent + " to "
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index f9730a9..eb1ab38 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1723,7 +1723,7 @@
     }
 
     void registerUserSwitchObserver(IUserSwitchObserver observer, String name) {
-        Preconditions.checkNotNull(name, "Observer name cannot be null");
+        Objects.requireNonNull(name, "Observer name cannot be null");
         checkCallingPermission(INTERACT_ACROSS_USERS_FULL, "registerUserSwitchObserver");
         mUserSwitchObservers.register(observer, name);
     }
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 8c9bff9..5bbb517 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -18,7 +18,6 @@
 
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
 import static android.app.AppOpsManager.NoteOpEvent;
-import static android.app.AppOpsManager.OpEventProxyInfo;
 import static android.app.AppOpsManager.OP_CAMERA;
 import static android.app.AppOpsManager.OP_COARSE_LOCATION;
 import static android.app.AppOpsManager.OP_FLAGS_ALL;
@@ -26,6 +25,7 @@
 import static android.app.AppOpsManager.OP_NONE;
 import static android.app.AppOpsManager.OP_PLAY_AUDIO;
 import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+import static android.app.AppOpsManager.OpEventProxyInfo;
 import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
 import static android.app.AppOpsManager.UID_STATE_CACHED;
 import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
@@ -40,9 +40,12 @@
 import static android.app.AppOpsManager.modeToName;
 import static android.app.AppOpsManager.opToName;
 import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState;
+import static android.content.Intent.ACTION_PACKAGE_REMOVED;
+import static android.content.Intent.EXTRA_REPLACING;
 import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
 
 import android.Manifest;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -69,6 +72,8 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PermissionInfo;
 import android.content.pm.UserInfo;
+import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils.ParsedFeature;
 import android.database.ContentObserver;
 import android.hardware.camera2.CameraDevice.CAMERA_AUDIO_RESTRICTION;
 import android.net.Uri;
@@ -98,6 +103,7 @@
 import android.util.KeyValueListParser;
 import android.util.LongSparseArray;
 import android.util.Pair;
+import android.util.Pools.SimplePool;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -122,6 +128,7 @@
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.LocalServices;
 import com.android.server.LockGuard;
+import com.android.server.SystemServerInitThreadPool;
 
 import libcore.util.EmptyArray;
 
@@ -195,16 +202,26 @@
     };
 
     private static final int MAX_UNFORWARED_OPS = 10;
+    private static final int MAX_UNUSED_POOLED_OBJECTS = 3;
 
     Context mContext;
     final AtomicFile mFile;
     final Handler mHandler;
 
+    /** Pool for {@link OpEventProxyInfoPool} to avoid to constantly reallocate new objects */
+    @GuardedBy("this")
+    private final OpEventProxyInfoPool mOpEventProxyInfoPool = new OpEventProxyInfoPool();
+
+    /** Pool for {@link InProgressStartOpEventPool} to avoid to constantly reallocate new objects */
+    @GuardedBy("this")
+    private final InProgressStartOpEventPool mInProgressStartOpEventPool =
+            new InProgressStartOpEventPool();
+
     private final AppOpsManagerInternalImpl mAppOpsManagerInternal
             = new AppOpsManagerInternalImpl();
 
     /**
-     * Registered callbacks, called from {@link #noteAsyncOp}.
+     * Registered callbacks, called from {@link #collectAsyncNotedOp}.
      *
      * <p>(package name, uid) -> callbacks
      *
@@ -215,7 +232,7 @@
             mAsyncOpWatchers = new ArrayMap<>();
 
     /**
-     * Async note-ops collected from {@link #noteAsyncOp} that have not been delivered to a
+     * Async note-ops collected from {@link #collectAsyncNotedOp} that have not been delivered to a
      * callback yet.
      *
      * <p>(package name, uid) -> list&lt;ops&gt;
@@ -266,6 +283,46 @@
     private SparseArray<List<Integer>> mSwitchOpToOps;
 
     /**
+     * An unsynchronized pool of {@link OpEventProxyInfo} objects.
+     */
+    private class OpEventProxyInfoPool extends SimplePool<OpEventProxyInfo> {
+        OpEventProxyInfoPool() {
+            super(MAX_UNUSED_POOLED_OBJECTS);
+        }
+
+        OpEventProxyInfo acquire(@IntRange(from = 0) int uid, @Nullable String packageName,
+                @Nullable String featureId) {
+            OpEventProxyInfo recycled = acquire();
+            if (recycled != null) {
+                recycled.reinit(uid, packageName, featureId);
+                return recycled;
+            }
+
+            return new OpEventProxyInfo(uid, packageName, featureId);
+        }
+    }
+
+    /**
+     * An unsynchronized pool of {@link InProgressStartOpEvent} objects.
+     */
+    private class InProgressStartOpEventPool extends SimplePool<InProgressStartOpEvent> {
+        InProgressStartOpEventPool() {
+            super(MAX_UNUSED_POOLED_OBJECTS);
+        }
+
+        InProgressStartOpEvent acquire(long startTime, long elapsedTime, @NonNull IBinder clientId,
+                @NonNull Runnable onDeath, int uidState) throws RemoteException {
+            InProgressStartOpEvent recycled = acquire();
+            if (recycled != null) {
+                recycled.reinit(startTime, elapsedTime, clientId, onDeath, uidState);
+                return recycled;
+            }
+
+            return new InProgressStartOpEvent(startTime, elapsedTime, clientId, onDeath, uidState);
+        }
+    }
+
+    /**
      * All times are in milliseconds. These constants are kept synchronized with the system
      * global Settings. Any access to this class or its fields should be done while
      * holding the AppOpsService lock.
@@ -468,6 +525,9 @@
         final UidState uidState;
         final boolean isPrivileged;
 
+        /** Lazily populated cache of featureIds of this package */
+        final @NonNull ArraySet<String> knownFeatureIds = new ArraySet<>();
+
         Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
             packageName = _packageName;
             uidState = _uidState;
@@ -478,43 +538,96 @@
     /** A in progress startOp->finishOp event */
     private static final class InProgressStartOpEvent implements IBinder.DeathRecipient {
         /** Wall clock time of startOp event (not monotonic) */
-        final long startTime;
+        private long mStartTime;
 
         /** Elapsed time since boot of startOp event */
-        final long startElapsedTime;
+        private long mStartElapsedTime;
 
         /** Id of the client that started the event */
-        final @NonNull IBinder clientId;
+        private @NonNull IBinder mClientId;
 
         /** To call when client dies */
-        final @NonNull Runnable onDeath;
+        private @NonNull Runnable mOnDeath;
 
         /** uidstate used when calling startOp */
-        final @AppOpsManager.UidState int uidState;
+        private @AppOpsManager.UidState int mUidState;
 
         /** How many times the op was started but not finished yet */
         int numUnfinishedStarts;
 
+        /**
+         * Create a new {@link InProgressStartOpEvent}.
+         *
+         * @param startTime The time {@link #startOperation} was called
+         * @param startElapsedTime The elapsed time when {@link #startOperation} was called
+         * @param clientId The client id of the caller of {@link #startOperation}
+         * @param onDeath The code to execute on client death
+         * @param uidState The uidstate of the app {@link #startOperation} was called for
+         *
+         * @throws RemoteException If the client is dying
+         */
         private InProgressStartOpEvent(long startTime, long startElapsedTime,
                 @NonNull IBinder clientId, @NonNull Runnable onDeath, int uidState)
                 throws RemoteException {
-            this.startTime = startTime;
-            this.startElapsedTime = startElapsedTime;
-            this.clientId = clientId;
-            this.onDeath = onDeath;
-            this.uidState = uidState;
+            mStartTime = startTime;
+            mStartElapsedTime = startElapsedTime;
+            mClientId = clientId;
+            mOnDeath = onDeath;
+            mUidState = uidState;
 
             clientId.linkToDeath(this, 0);
         }
 
         /** Clean up event */
         public void finish() {
-            clientId.unlinkToDeath(this, 0);
+            mClientId.unlinkToDeath(this, 0);
         }
 
         @Override
         public void binderDied() {
-            onDeath.run();
+            mOnDeath.run();
+        }
+
+        /**
+         * Reinit existing object with new state.
+         *
+         * @param startTime The time {@link #startOperation} was called
+         * @param startElapsedTime The elapsed time when {@link #startOperation} was called
+         * @param clientId The client id of the caller of {@link #startOperation}
+         * @param onDeath The code to execute on client death
+         * @param uidState The uidstate of the app {@link #startOperation} was called for
+         *
+         * @throws RemoteException If the client is dying
+         */
+        public void reinit(long startTime, long startElapsedTime, @NonNull IBinder clientId,
+                @NonNull Runnable onDeath, int uidState) throws RemoteException {
+            mStartTime = startTime;
+            mStartElapsedTime = startElapsedTime;
+            mClientId = clientId;
+            mOnDeath = onDeath;
+            mUidState = uidState;
+
+            clientId.linkToDeath(this, 0);
+        }
+
+        /** @return Wall clock time of startOp event */
+        public long getStartTime() {
+            return mStartTime;
+        }
+
+        /** @return Elapsed time since boot of startOp event */
+        public long getStartElapsedTime() {
+            return mStartElapsedTime;
+        }
+
+        /** @return Id of the client that started the event */
+        public @NonNull IBinder getClientId() {
+            return mClientId;
+        }
+
+        /** @return uidstate used when calling startOp */
+        public int getUidState() {
+            return mUidState;
         }
     }
 
@@ -527,7 +640,7 @@
          * <p>Key is {@link AppOpsManager#makeKey}
          */
         @GuardedBy("AppOpsService.this")
-        private @Nullable LongSparseArray<AppOpsManager.NoteOpEvent> mAccessEvents;
+        private @Nullable LongSparseArray<NoteOpEvent> mAccessEvents;
 
         /**
          * Last rejected accesses for each uidState/opFlag combination
@@ -535,7 +648,7 @@
          * <p>Key is {@link AppOpsManager#makeKey}
          */
         @GuardedBy("AppOpsService.this")
-        private @Nullable LongSparseArray<AppOpsManager.NoteOpEvent> mRejectEvents;
+        private @Nullable LongSparseArray<NoteOpEvent> mRejectEvents;
 
         /**
          * Currently in progress startOp events
@@ -587,9 +700,16 @@
 
             OpEventProxyInfo proxyInfo = null;
             if (proxyUid != Process.INVALID_UID) {
-                proxyInfo = new OpEventProxyInfo(proxyUid, proxyPackageName, proxyFeatureId);
+                proxyInfo = mOpEventProxyInfoPool.acquire(proxyUid, proxyPackageName,
+                        proxyFeatureId);
             }
-            mAccessEvents.put(key, new NoteOpEvent(noteTime, duration, proxyInfo));
+
+            NoteOpEvent existingEvent = mAccessEvents.get(key);
+            if (existingEvent != null) {
+                existingEvent.reinit(noteTime, duration, proxyInfo, mOpEventProxyInfoPool);
+            } else {
+                mAccessEvents.put(key, new NoteOpEvent(noteTime, duration, proxyInfo));
+            }
         }
 
         /**
@@ -618,7 +738,12 @@
             }
 
             // We do not collect proxy information for rejections yet
-            mRejectEvents.put(key, new NoteOpEvent(noteTime, -1, null));
+            NoteOpEvent existingEvent = mRejectEvents.get(key);
+            if (existingEvent != null) {
+                existingEvent.reinit(noteTime, -1, null, mOpEventProxyInfoPool);
+            } else {
+                mRejectEvents.put(key, new NoteOpEvent(noteTime, -1, null));
+            }
         }
 
         /**
@@ -638,28 +763,15 @@
                 mInProgressEvents = new ArrayMap<>(1);
             }
 
-
             InProgressStartOpEvent event = mInProgressEvents.get(clientId);
             if (event == null) {
-                event = new InProgressStartOpEvent(System.currentTimeMillis(),
-                        SystemClock.elapsedRealtime(), clientId, () -> {
-                    // In the case the client dies without calling finish first
-                    synchronized (AppOpsService.this) {
-                        if (mInProgressEvents == null) {
-                            return;
-                        }
-
-                        InProgressStartOpEvent deadEvent = mInProgressEvents.get(clientId);
-                        if (deadEvent != null) {
-                            deadEvent.numUnfinishedStarts = 1;
-                        }
-
-                        finished(clientId);
-                    }
-                }, uidState);
+                event = mInProgressStartOpEventPool.acquire(System.currentTimeMillis(),
+                        SystemClock.elapsedRealtime(), clientId,
+                        PooledLambda.obtainRunnable(AppOpsService::onClientDeath, this, clientId),
+                        uidState);
                 mInProgressEvents.put(clientId, event);
             } else {
-                if (uidState != event.uidState) {
+                if (uidState != event.mUidState) {
                     onUidStateChanged(uidState);
                 }
             }
@@ -703,13 +815,15 @@
                 }
 
                 // startOp events don't support proxy, hence use flags==SELF
-                NoteOpEvent finishedEvent = new NoteOpEvent(event.startTime,
-                        SystemClock.elapsedRealtime() - event.startElapsedTime, null);
-                mAccessEvents.put(makeKey(event.uidState, OP_FLAG_SELF), finishedEvent);
+                NoteOpEvent finishedEvent = new NoteOpEvent(event.getStartTime(),
+                        SystemClock.elapsedRealtime() - event.getStartElapsedTime(), null);
+                mAccessEvents.put(makeKey(event.getUidState(), OP_FLAG_SELF), finishedEvent);
 
                 mHistoricalRegistry.increaseOpAccessDuration(parent.op, parent.uid,
-                        parent.packageName, event.uidState, AppOpsManager.OP_FLAG_SELF,
-                        finishedEvent.duration);
+                        parent.packageName, event.getUidState(), AppOpsManager.OP_FLAG_SELF,
+                        finishedEvent.getDuration());
+
+                mInProgressStartOpEventPool.release(event);
 
                 if (mInProgressEvents.isEmpty()) {
                     mInProgressEvents = null;
@@ -724,6 +838,26 @@
         }
 
         /**
+         * Called in the case the client dies without calling finish first
+         *
+         * @param clientId The client that died
+         */
+        void onClientDeath(@NonNull IBinder clientId) {
+            synchronized (AppOpsService.this) {
+                if (mInProgressEvents == null) {
+                    return;
+                }
+
+                InProgressStartOpEvent deadEvent = mInProgressEvents.get(clientId);
+                if (deadEvent != null) {
+                    deadEvent.numUnfinishedStarts = 1;
+                }
+
+                finished(clientId);
+            }
+        }
+
+        /**
          * Notify that the state of the uid changed
          *
          * @param newState The new state
@@ -737,10 +871,10 @@
             for (int i = 0; i < numInProgressEvents; i++) {
                 InProgressStartOpEvent event = mInProgressEvents.valueAt(i);
 
-                if (event.uidState != newState) {
+                if (event.getUidState() != newState) {
                     try {
-                        finished(event.clientId, false);
-                        started(event.clientId, newState);
+                        finished(event.getClientId(), false);
+                        started(event.getClientId(), newState);
                     } catch (RemoteException e) {
                         if (DEBUG) Slog.e(TAG, "Cannot switch to new uidState " + newState);
                     }
@@ -748,6 +882,59 @@
             }
         }
 
+        /**
+         * Combine {@code a} and {@code b} and return the result. The result might be {@code a}
+         * or {@code b}. If there is an event for the same key in both the later event is retained.
+         */
+        private @Nullable LongSparseArray<NoteOpEvent> add(@Nullable LongSparseArray<NoteOpEvent> a,
+                @Nullable LongSparseArray<NoteOpEvent> b) {
+            if (a == null) {
+                return b;
+            }
+
+            if (b == null) {
+                return a;
+            }
+
+            int numEventsToAdd = b.size();
+            for (int i = 0; i < numEventsToAdd; i++) {
+                long keyOfEventToAdd = b.keyAt(i);
+                NoteOpEvent bEvent = b.valueAt(i);
+                NoteOpEvent aEvent = a.get(keyOfEventToAdd);
+
+                if (aEvent == null || bEvent.getNoteTime() > aEvent.getNoteTime()) {
+                    a.put(keyOfEventToAdd, bEvent);
+                }
+            }
+
+            return a;
+        }
+
+        /**
+         * Add all data from the {@code featureToAdd} to this op.
+         *
+         * <p>If there is an event for the same key in both the later event is retained.
+         * <p>{@code opToAdd} should not be used after this method is called.
+         *
+         * @param opToAdd The op to add
+         */
+        public void add(@NonNull FeatureOp opToAdd) {
+            if (opToAdd.mInProgressEvents != null) {
+                Slog.w(TAG, "Ignoring " + opToAdd.mInProgressEvents.size() + " running app-ops");
+
+                int numInProgressEvents = opToAdd.mInProgressEvents.size();
+                for (int i = 0; i < numInProgressEvents; i++) {
+                    InProgressStartOpEvent event = opToAdd.mInProgressEvents.valueAt(i);
+
+                    event.finish();
+                    mInProgressStartOpEventPool.release(event);
+                }
+            }
+
+            mAccessEvents = add(mAccessEvents, opToAdd.mAccessEvents);
+            mRejectEvents = add(mRejectEvents, opToAdd.mRejectEvents);
+        }
+
         public boolean isRunning() {
             return mInProgressEvents != null;
         }
@@ -757,12 +944,27 @@
                     || (mRejectEvents != null && mRejectEvents.size() > 0);
         }
 
-        @NonNull OpFeatureEntry createFeatureEntryLocked() {
-            LongSparseArray<NoteOpEvent> accessEvents = null;
-            if (mAccessEvents != null) {
-                accessEvents = mAccessEvents.clone();
+        /**
+         * Clone a {@link LongSparseArray} and clone all values.
+         */
+        private @Nullable LongSparseArray<NoteOpEvent> deepClone(
+                @Nullable LongSparseArray<NoteOpEvent> original) {
+            if (original == null) {
+                return original;
             }
 
+            int size = original.size();
+            LongSparseArray<NoteOpEvent> clone = new LongSparseArray<>(size);
+            for (int i = 0; i < size; i++) {
+                clone.put(original.keyAt(i), new NoteOpEvent(original.valueAt(i)));
+            }
+
+            return clone;
+        }
+
+        @NonNull OpFeatureEntry createFeatureEntryLocked() {
+            LongSparseArray<NoteOpEvent> accessEvents = deepClone(mAccessEvents);
+
             // Add in progress events as access events
             if (mInProgressEvents != null) {
                 long now = SystemClock.elapsedRealtime();
@@ -776,15 +978,13 @@
                     InProgressStartOpEvent event = mInProgressEvents.valueAt(i);
 
                     // startOp events don't support proxy
-                    accessEvents.append(makeKey(event.uidState, OP_FLAG_SELF),
-                            new NoteOpEvent(event.startTime, now - event.startElapsedTime, null));
+                    accessEvents.append(makeKey(event.getUidState(), OP_FLAG_SELF),
+                            new NoteOpEvent(event.getStartTime(), now - event.getStartElapsedTime(),
+                                    null));
                 }
             }
 
-            LongSparseArray<NoteOpEvent> rejectEvents = null;
-            if (mRejectEvents != null) {
-                rejectEvents = mRejectEvents.clone();
-            }
+            LongSparseArray<NoteOpEvent> rejectEvents = deepClone(mRejectEvents);
 
             return new OpFeatureEntry(parent.op, isRunning(), accessEvents, rejectEvents);
         }
@@ -1024,6 +1224,13 @@
         }
     }
 
+    /**
+     * Call {@link FeatureOp#onClientDeath featureOp.onClientDeath(clientId)}.
+     */
+    private static void onClientDeath(@NonNull FeatureOp featureOp, @NonNull IBinder clientId) {
+        featureOp.onClientDeath(clientId);
+    }
+
     public AppOpsService(File storagePath, Handler handler) {
         LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
         mFile = new AtomicFile(storagePath, "appops");
@@ -1038,20 +1245,110 @@
         LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
     }
 
+    /** Handler for work when packages are removed or updated */
+    private BroadcastReceiver mOnPackageUpdatedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            String pkgName = intent.getData().getEncodedSchemeSpecificPart();
+            int uid = intent.getIntExtra(Intent.EXTRA_UID, Process.INVALID_UID);
+
+            if (action.equals(ACTION_PACKAGE_REMOVED) && !intent.hasExtra(EXTRA_REPLACING)) {
+                synchronized (AppOpsService.this) {
+                    UidState uidState = mUidStates.get(uid);
+                    if (uidState == null || uidState.pkgOps == null) {
+                        return;
+                    }
+
+                    Ops removedOps = uidState.pkgOps.remove(pkgName);
+                    if (removedOps != null) {
+                        scheduleFastWriteLocked();
+                    }
+                }
+            } else if (action.equals(Intent.ACTION_PACKAGE_REPLACED)) {
+                AndroidPackage pkg = LocalServices.getService(
+                        PackageManagerInternal.class).getPackage(pkgName);
+                if (pkg == null) {
+                    return;
+                }
+
+                ArrayMap<String, String> dstFeatureIds = new ArrayMap<>();
+                ArraySet<String> featureIds = new ArraySet<>();
+                if (pkg.getFeatures() != null) {
+                    int numFeatures = pkg.getFeatures().size();
+                    for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
+                        ParsedFeature feature = pkg.getFeatures().get(featureNum);
+                        featureIds.add(feature.id);
+
+                        int numInheritFrom = feature.inheritFrom.size();
+                        for (int inheritFromNum = 0; inheritFromNum < numInheritFrom;
+                                inheritFromNum++) {
+                            dstFeatureIds.put(feature.inheritFrom.get(inheritFromNum),
+                                    feature.id);
+                        }
+                    }
+                }
+
+                synchronized (AppOpsService.this) {
+                    UidState uidState = mUidStates.get(uid);
+                    if (uidState == null || uidState.pkgOps == null) {
+                        return;
+                    }
+
+                    Ops ops = uidState.pkgOps.get(pkgName);
+                    if (ops == null) {
+                        return;
+                    }
+
+                    ops.knownFeatureIds.clear();
+                    int numOps = ops.size();
+                    for (int opNum = 0; opNum < numOps; opNum++) {
+                        Op op = ops.valueAt(opNum);
+
+                        int numFeatures = op.mFeatures.size();
+                        for (int featureNum = numFeatures - 1; featureNum >= 0; featureNum--) {
+                            String featureId = op.mFeatures.keyAt(featureNum);
+
+                            if (featureIds.contains(featureId)) {
+                                // feature still exist after upgrade
+                                continue;
+                            }
+
+                            String newFeatureId = dstFeatureIds.get(featureId);
+
+                            FeatureOp newFeatureOp = op.getOrCreateFeature(op, newFeatureId);
+                            newFeatureOp.add(op.mFeatures.valueAt(featureNum));
+                            op.mFeatures.removeAt(featureNum);
+
+                            scheduleFastWriteLocked();
+                        }
+                    }
+                }
+            }
+        }
+    };
+
     public void systemReady() {
         mConstants.startMonitoring(mContext.getContentResolver());
         mHistoricalRegistry.systemReady(mContext.getContentResolver());
 
-        synchronized (this) {
-            boolean changed = false;
-            for (int i = mUidStates.size() - 1; i >= 0; i--) {
-                UidState uidState = mUidStates.valueAt(i);
+        IntentFilter packageUpdateFilter = new IntentFilter();
+        packageUpdateFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        packageUpdateFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+        packageUpdateFilter.addDataScheme("package");
 
-                String[] packageNames = getPackagesForUid(uidState.uid);
-                if (ArrayUtils.isEmpty(packageNames)) {
+        mContext.registerReceiver(mOnPackageUpdatedReceiver, packageUpdateFilter);
+
+        synchronized (this) {
+            for (int uidNum = mUidStates.size() - 1; uidNum >= 0; uidNum--) {
+                int uid = mUidStates.keyAt(uidNum);
+                UidState uidState = mUidStates.valueAt(uidNum);
+
+                String[] pkgsInUid = getPackagesForUid(uidState.uid);
+                if (ArrayUtils.isEmpty(pkgsInUid)) {
                     uidState.clear();
-                    mUidStates.removeAt(i);
-                    changed = true;
+                    mUidStates.removeAt(uidNum);
+                    scheduleFastWriteLocked();
                     continue;
                 }
 
@@ -1060,31 +1357,24 @@
                     continue;
                 }
 
-                Iterator<Ops> it = pkgs.values().iterator();
-                while (it.hasNext()) {
-                    Ops ops = it.next();
-                    int curUid = -1;
-                    try {
-                        curUid = AppGlobals.getPackageManager().getPackageUid(ops.packageName,
-                                PackageManager.MATCH_UNINSTALLED_PACKAGES,
-                                UserHandle.getUserId(ops.uidState.uid));
-                    } catch (RemoteException ignored) {
-                    }
-                    if (curUid != ops.uidState.uid) {
-                        Slog.i(TAG, "Pruning old package " + ops.packageName
-                                + "/" + ops.uidState + ": new uid=" + curUid);
-                        it.remove();
-                        changed = true;
-                    }
-                }
+                int numPkgs = pkgs.size();
+                for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
+                    String pkg = pkgs.keyAt(pkgNum);
 
-                if (uidState.isDefault()) {
-                    mUidStates.removeAt(i);
+                    String action;
+                    if (!ArrayUtils.contains(pkgsInUid, pkg)) {
+                        action = Intent.ACTION_PACKAGE_REMOVED;
+                    } else {
+                        action = Intent.ACTION_PACKAGE_REPLACED;
+                    }
+
+                    SystemServerInitThreadPool.submit(
+                            () -> mOnPackageUpdatedReceiver.onReceive(mContext, new Intent(action)
+                                    .setData(Uri.fromParts("package", pkg, null))
+                                    .putExtra(Intent.EXTRA_UID, uid)),
+                            "Update app-ops uidState in case package " + pkg + " changed");
                 }
             }
-            if (changed) {
-                scheduleFastWriteLocked();
-            }
         }
 
         final IntentFilter packageSuspendFilter = new IntentFilter();
@@ -1146,11 +1436,13 @@
                                 return Zygote.MOUNT_EXTERNAL_NONE;
                             }
                             if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
-                                    packageName, null) != AppOpsManager.MODE_ALLOWED) {
+                                    packageName, null, true, "External storage policy")
+                                    != AppOpsManager.MODE_ALLOWED) {
                                 return Zygote.MOUNT_EXTERNAL_NONE;
                             }
                             if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
-                                    packageName, null) != AppOpsManager.MODE_ALLOWED) {
+                                    packageName, null, true, "External storage policy")
+                                    != AppOpsManager.MODE_ALLOWED) {
                                 return Zygote.MOUNT_EXTERNAL_READ;
                             }
                             return Zygote.MOUNT_EXTERNAL_WRITE;
@@ -1198,7 +1490,7 @@
                         FeatureOp featureOp = op.mFeatures.valueAt(featureNum);
 
                         while (featureOp.mInProgressEvents != null) {
-                            featureOp.mInProgressEvents.valueAt(0).onDeath.run();
+                            featureOp.finished(featureOp.mInProgressEvents.keyAt(0));
                         }
                     }
                 }
@@ -1388,7 +1680,7 @@
             return Collections.emptyList();
         }
         synchronized (this) {
-            Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* isPrivileged */,
+            Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, null, false /* isPrivileged */,
                     false /* edit */);
             if (pkgOps == null) {
                 return null;
@@ -1417,7 +1709,7 @@
                 .setOpNames(opNames)
                 .setFlags(flags)
                 .build();
-        Preconditions.checkNotNull(callback, "callback cannot be null");
+        Objects.requireNonNull(callback, "callback cannot be null");
 
         mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
                 Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
@@ -1442,7 +1734,7 @@
                 .setOpNames(opNames)
                 .setFlags(flags)
                 .build();
-        Preconditions.checkNotNull(callback, "callback cannot be null");
+        Objects.requireNonNull(callback, "callback cannot be null");
 
         mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
                 Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
@@ -1488,7 +1780,7 @@
         op.removeFeaturesWithNoTime();
 
         if (op.mFeatures.size() == 0) {
-            Ops ops = getOpsRawLocked(uid, packageName, false /* isPrivileged */,
+            Ops ops = getOpsRawLocked(uid, packageName, null, false /* isPrivileged */,
                     false /* edit */);
             if (ops != null) {
                 ops.remove(op.op);
@@ -1752,7 +2044,7 @@
 
         boolean isPrivileged;
         try {
-            isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
+            isPrivileged = verifyAndGetIsPrivileged(uid, packageName, null);
         } catch (SecurityException e) {
             Slog.e(TAG, "Cannot setMode", e);
             return;
@@ -1767,7 +2059,7 @@
 
         synchronized (this) {
             UidState uidState = getUidStateLocked(uid, false);
-            Op op = getOpLocked(code, uid, packageName, isPrivileged, true);
+            Op op = getOpLocked(code, uid, packageName, null, isPrivileged, true);
             if (op != null) {
                 if (op.mode != mode) {
                     op.mode = mode;
@@ -2137,7 +2429,7 @@
         boolean isPrivileged;
 
         try {
-            isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
+            isPrivileged = verifyAndGetIsPrivileged(uid, packageName, null);
         } catch (SecurityException e) {
             Slog.e(TAG, "checkOperation", e);
             return AppOpsManager.opToDefaultMode(code);
@@ -2147,7 +2439,7 @@
             return AppOpsManager.MODE_IGNORED;
         }
         synchronized (this) {
-            if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) {
+            if (isOpRestrictedLocked(uid, code, packageName, null, isPrivileged)) {
                 return AppOpsManager.MODE_IGNORED;
             }
             code = AppOpsManager.opToSwitch(code);
@@ -2157,7 +2449,7 @@
                 final int rawMode = uidState.opModes.get(code);
                 return raw ? rawMode : uidState.evalMode(code, rawMode);
             }
-            Op op = getOpLocked(code, uid, packageName, false, false);
+            Op op = getOpLocked(code, uid, packageName, null, false, false);
             if (op == null) {
                 return AppOpsManager.opToDefaultMode(code);
             }
@@ -2218,9 +2510,9 @@
 
     @Override
     public int checkPackage(int uid, String packageName) {
-        Preconditions.checkNotNull(packageName);
+        Objects.requireNonNull(packageName);
         try {
-            verifyAndGetIsPrivileged(uid, packageName);
+            verifyAndGetIsPrivileged(uid, packageName, null);
 
             return AppOpsManager.MODE_ALLOWED;
         } catch (SecurityException ignored) {
@@ -2231,7 +2523,7 @@
     @Override
     public int noteProxyOperation(int code, int proxiedUid, String proxiedPackageName,
             String proxiedFeatureId, int proxyUid, String proxyPackageName,
-            String proxyFeatureId) {
+            String proxyFeatureId, boolean shouldCollectAsyncNotedOp, String message) {
         verifyIncomingUid(proxyUid);
         verifyIncomingOp(code);
 
@@ -2247,7 +2539,8 @@
         final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
                 : AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;
         final int proxyMode = noteOperationUnchecked(code, proxyUid, resolveProxyPackageName,
-                proxyFeatureId, Process.INVALID_UID, null, null, proxyFlags);
+                proxyFeatureId, Process.INVALID_UID, null, null, proxyFlags,
+                !isProxyTrusted, "proxy " + message);
         if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
             return proxyMode;
         }
@@ -2260,23 +2553,27 @@
                 : AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED;
         return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
                 proxiedFeatureId, proxyUid, resolveProxyPackageName, proxyFeatureId,
-                proxiedFlags);
+                proxiedFlags, shouldCollectAsyncNotedOp, message);
     }
 
     @Override
-    public int noteOperation(int code, int uid, String packageName, String featureId) {
+    public int noteOperation(int code, int uid, String packageName, String featureId,
+            boolean shouldCollectAsyncNotedOp, String message) {
         final CheckOpsDelegate delegate;
         synchronized (this) {
             delegate = mCheckOpsDelegate;
         }
         if (delegate == null) {
-            return noteOperationImpl(code, uid, packageName, featureId);
+            return noteOperationImpl(code, uid, packageName, featureId, shouldCollectAsyncNotedOp,
+                    message);
         }
-        return delegate.noteOperation(code, uid, packageName, featureId,
-                AppOpsService.this::noteOperationImpl);
+        return delegate.noteOperation(code, uid, packageName, featureId, shouldCollectAsyncNotedOp,
+                message, AppOpsService.this::noteOperationImpl);
     }
 
-    private int noteOperationImpl(int code, int uid, String packageName, String featureId) {
+    private int noteOperationImpl(int code, int uid, @Nullable String packageName,
+            @Nullable String featureId, boolean shouldCollectAsyncNotedOp,
+            @Nullable String message) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
         String resolvedPackageName = resolvePackageName(uid, packageName);
@@ -2284,24 +2581,25 @@
             return AppOpsManager.MODE_IGNORED;
         }
         return noteOperationUnchecked(code, uid, resolvedPackageName, featureId,
-                Process.INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF);
+                Process.INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF,
+                shouldCollectAsyncNotedOp, message);
     }
 
-    private int noteOperationUnchecked(int code, int uid, String packageName, String featureId,
-            int proxyUid, String proxyPackageName, @Nullable String proxyFeatureId,
-            @OpFlags int flags) {
-        // TODO moltmann: Verify that feature is declared in package
-
+    private int noteOperationUnchecked(int code, int uid, @NonNull String packageName,
+            @Nullable String featureId, int proxyUid, String proxyPackageName,
+            @Nullable String proxyFeatureId, @OpFlags int flags, boolean shouldCollectAsyncNotedOp,
+            @Nullable String message) {
         boolean isPrivileged;
         try {
-            isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
+            isPrivileged = verifyAndGetIsPrivileged(uid, packageName, featureId);
         } catch (SecurityException e) {
             Slog.e(TAG, "noteOperation", e);
             return AppOpsManager.MODE_ERRORED;
         }
 
         synchronized (this) {
-            final Ops ops = getOpsRawLocked(uid, packageName, isPrivileged, true /* edit */);
+            final Ops ops = getOpsRawLocked(uid, packageName, featureId, isPrivileged,
+                    true /* edit */);
             if (ops == null) {
                 scheduleOpNotedIfNeededLocked(code, uid, packageName,
                         AppOpsManager.MODE_IGNORED);
@@ -2309,9 +2607,9 @@
                         + " package " + packageName);
                 return AppOpsManager.MODE_ERRORED;
             }
-            final Op op = getOpLocked(ops, code, true);
+            final Op op = getOpLocked(ops, code, uid, true);
             final FeatureOp featureOp = op.getOrCreateFeature(op, featureId);
-            if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) {
+            if (isOpRestrictedLocked(uid, code, packageName, featureId, isPrivileged)) {
                 scheduleOpNotedIfNeededLocked(code, uid, packageName,
                         AppOpsManager.MODE_IGNORED);
                 return AppOpsManager.MODE_IGNORED;
@@ -2320,7 +2618,7 @@
             if (featureOp.isRunning()) {
                 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName + " code "
                         + code + " startTime of in progress event="
-                        + featureOp.mInProgressEvents.valueAt(0).startTime);
+                        + featureOp.mInProgressEvents.valueAt(0).getStartTime());
             }
 
             final int switchCode = AppOpsManager.opToSwitch(code);
@@ -2339,7 +2637,8 @@
                     return uidMode;
                 }
             } else {
-                final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
+                final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true)
+                        : op;
                 final int mode = switchOp.evalMode();
                 if (mode != AppOpsManager.MODE_ALLOWED) {
                     if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
@@ -2360,6 +2659,11 @@
                     uidState.state, flags);
             scheduleOpNotedIfNeededLocked(code, uid, packageName,
                     AppOpsManager.MODE_ALLOWED);
+
+            if (shouldCollectAsyncNotedOp) {
+                collectAsyncNotedOp(uid, packageName, code, featureId, message);
+            }
+
             return AppOpsManager.MODE_ALLOWED;
         }
     }
@@ -2425,7 +2729,7 @@
         Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
         Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
                 "Invalid op code in: " + Arrays.toString(ops));
-        Preconditions.checkNotNull(callback, "Callback cannot be null");
+        Objects.requireNonNull(callback, "Callback cannot be null");
         synchronized (this) {
             SparseArray<NotedCallback> callbacks = mNotedWatchers.get(callback.asBinder());
             if (callbacks == null) {
@@ -2442,7 +2746,7 @@
 
     @Override
     public void stopWatchingNoted(IAppOpsNotedCallback callback) {
-        Preconditions.checkNotNull(callback, "Callback cannot be null");
+        Objects.requireNonNull(callback, "Callback cannot be null");
         synchronized (this) {
             final SparseArray<NotedCallback> notedCallbacks =
                     mNotedWatchers.remove(callback.asBinder());
@@ -2456,21 +2760,20 @@
         }
     }
 
-    @Override
-    public void noteAsyncOp(String callingPackageName, int uid, String packageName, int opCode,
-            String featureId, String message) {
-        Preconditions.checkNotNull(message);
-        verifyAndGetIsPrivileged(uid, packageName);
-
-        verifyIncomingUid(uid);
-        verifyIncomingOp(opCode);
+    /**
+     * Collect an {@link AsyncNotedAppOp}.
+     *
+     * @param uid The uid the op was noted for
+     * @param packageName The package the op was noted for
+     * @param opCode The code of the op noted
+     * @param featureId The id of the feature to op was noted for
+     * @param message The message for the op noting
+     */
+    private void collectAsyncNotedOp(int uid, @NonNull String packageName, int opCode,
+            @Nullable String featureId, @NonNull String message) {
+        Objects.requireNonNull(message);
 
         int callingUid = Binder.getCallingUid();
-        long now = System.currentTimeMillis();
-
-        if (callingPackageName != null) {
-            verifyAndGetIsPrivileged(callingUid, callingPackageName);
-        }
 
         long token = Binder.clearCallingIdentity();
         try {
@@ -2479,7 +2782,7 @@
 
                 RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
                 AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid,
-                        callingPackageName, featureId, message, now);
+                        featureId, message, System.currentTimeMillis());
                 final boolean[] wasNoteForwarded = {false};
 
                 if (callbacks != null) {
@@ -2528,13 +2831,13 @@
 
     @Override
     public void startWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback) {
-        Preconditions.checkNotNull(packageName);
-        Preconditions.checkNotNull(callback);
+        Objects.requireNonNull(packageName);
+        Objects.requireNonNull(callback);
 
         int uid = Binder.getCallingUid();
         Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
 
-        verifyAndGetIsPrivileged(uid, packageName);
+        verifyAndGetIsPrivileged(uid, packageName, null);
 
         synchronized (this) {
             RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
@@ -2558,13 +2861,13 @@
 
     @Override
     public void stopWatchingAsyncNoted(String packageName, IAppOpsAsyncNotedCallback callback) {
-        Preconditions.checkNotNull(packageName);
-        Preconditions.checkNotNull(callback);
+        Objects.requireNonNull(packageName);
+        Objects.requireNonNull(callback);
 
         int uid = Binder.getCallingUid();
         Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
 
-        verifyAndGetIsPrivileged(uid, packageName);
+        verifyAndGetIsPrivileged(uid, packageName, null);
 
         synchronized (this) {
             RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
@@ -2579,11 +2882,11 @@
 
     @Override
     public List<AsyncNotedAppOp> extractAsyncOps(String packageName) {
-        Preconditions.checkNotNull(packageName);
+        Objects.requireNonNull(packageName);
 
         int uid = Binder.getCallingUid();
 
-        verifyAndGetIsPrivileged(uid, packageName);
+        verifyAndGetIsPrivileged(uid, packageName, null);
 
         synchronized (this) {
             return mUnforwardedAsyncNotedOps.remove(getAsyncNotedOpsKey(packageName, uid));
@@ -2592,7 +2895,8 @@
 
     @Override
     public int startOperation(IBinder clientId, int code, int uid, String packageName,
-            String featureId, boolean startIfModeDefault) {
+            String featureId, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
+            String message) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
         String resolvedPackageName = resolvePackageName(uid, packageName);
@@ -2602,22 +2906,22 @@
 
         boolean isPrivileged;
         try {
-            isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
+            isPrivileged = verifyAndGetIsPrivileged(uid, packageName, featureId);
         } catch (SecurityException e) {
             Slog.e(TAG, "startOperation", e);
             return AppOpsManager.MODE_ERRORED;
         }
 
         synchronized (this) {
-            final Ops ops = getOpsRawLocked(uid, resolvedPackageName, isPrivileged,
+            final Ops ops = getOpsRawLocked(uid, resolvedPackageName, featureId, isPrivileged,
                     true /* edit */);
             if (ops == null) {
                 if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
                         + " package " + resolvedPackageName);
                 return AppOpsManager.MODE_ERRORED;
             }
-            final Op op = getOpLocked(ops, code, true);
-            if (isOpRestrictedLocked(uid, code, resolvedPackageName, isPrivileged)) {
+            final Op op = getOpLocked(ops, code, uid, true);
+            if (isOpRestrictedLocked(uid, code, resolvedPackageName, featureId, isPrivileged)) {
                 return AppOpsManager.MODE_IGNORED;
             }
             final FeatureOp featureOp = op.getOrCreateFeature(op, featureId);
@@ -2639,7 +2943,8 @@
                     return uidMode;
                 }
             } else {
-                final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
+                final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true)
+                        : op;
                 final int mode = switchOp.evalMode();
                 if (mode != AppOpsManager.MODE_ALLOWED
                         && (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
@@ -2662,6 +2967,10 @@
             }
         }
 
+        if (shouldCollectAsyncNotedOp) {
+            collectAsyncNotedOp(uid, packageName, code, featureId, message);
+        }
+
         return AppOpsManager.MODE_ALLOWED;
     }
 
@@ -2677,14 +2986,14 @@
 
         boolean isPrivileged;
         try {
-            isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
+            isPrivileged = verifyAndGetIsPrivileged(uid, packageName, featureId);
         } catch (SecurityException e) {
             Slog.e(TAG, "Cannot finishOperation", e);
             return;
         }
 
         synchronized (this) {
-            Op op = getOpLocked(code, uid, resolvedPackageName, isPrivileged, true);
+            Op op = getOpLocked(code, uid, resolvedPackageName, featureId, isPrivileged, true);
             if (op == null) {
                 return;
             }
@@ -2915,22 +3224,24 @@
      *
      * @param uid The uid the package belongs to
      * @param packageName The package the might belong to the uid
+     * @param featureId The feature in the package or {@code null} if no need to verify
      *
      * @return {@code true} iff the package is privileged
      */
-    private boolean verifyAndGetIsPrivileged(int uid, String packageName) {
+    private boolean verifyAndGetIsPrivileged(int uid, String packageName,
+            @Nullable String featureId) {
         if (uid == Process.ROOT_UID) {
             // For backwards compatibility, don't check package name for root UID.
             return false;
         }
 
-        // Do not check if uid/packageName is already known
+        // Do not check if uid/packageName/featureId is already known
         synchronized (this) {
             UidState uidState = mUidStates.get(uid);
             if (uidState != null && uidState.pkgOps != null) {
                 Ops ops = uidState.pkgOps.get(packageName);
 
-                if (ops != null) {
+                if (ops != null && (featureId == null || ops.knownFeatureIds.contains(featureId))) {
                     return ops.isPrivileged;
                 }
             }
@@ -2940,19 +3251,31 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             int pkgUid;
+            AndroidPackage pkg = LocalServices.getService(PackageManagerInternal.class).getPackage(
+                    packageName);
+            boolean isFeatureIdValid = false;
 
-            ApplicationInfo appInfo = LocalServices.getService(PackageManagerInternal.class)
-                    .getApplicationInfo(packageName, PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-                                    | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
-                                    | PackageManager.MATCH_UNINSTALLED_PACKAGES
-                                    | PackageManager.MATCH_INSTANT,
-                            Process.SYSTEM_UID, UserHandle.getUserId(uid));
-            if (appInfo != null) {
-                pkgUid = appInfo.uid;
-                isPrivileged = (appInfo.privateFlags
-                        & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
+            if (pkg != null) {
+                if (featureId == null) {
+                    isFeatureIdValid = true;
+                } else {
+                    if (pkg.getFeatures() != null) {
+                        int numFeatures = pkg.getFeatures().size();
+                        for (int i = 0; i < numFeatures; i++) {
+                            if (pkg.getFeatures().get(i).id.equals(featureId)) {
+                                isFeatureIdValid = true;
+                            }
+                        }
+                    }
+                }
+
+                pkgUid = UserHandle.getUid(
+                        UserHandle.getUserId(uid), UserHandle.getAppId(pkg.getUid()));
+                isPrivileged = pkg.isPrivileged();
             } else {
+                // Allow any feature id for resolvable uids
+                isFeatureIdValid = true;
+
                 pkgUid = resolveUid(packageName);
                 if (pkgUid >= 0) {
                     isPrivileged = false;
@@ -2962,6 +3285,12 @@
                 throw new SecurityException("Specified package " + packageName + " under uid " + uid
                         + " but it is really " + pkgUid);
             }
+
+            if (!isFeatureIdValid) {
+                // TODO moltmann: Switch from logging to enforcement
+                Slog.e(TAG, "featureId " + featureId + " not declared in manifest of "
+                        + packageName);
+            }
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -2974,12 +3303,14 @@
      *
      * @param uid The uid the package belongs to
      * @param packageName The name of the package
+     * @param featureId The feature in the package
      * @param isPrivileged If the package is privilidged (ignored if {@code edit} is false)
      * @param edit If an ops does not exist, create the ops?
 
      * @return
      */
-    private Ops getOpsRawLocked(int uid, String packageName, boolean isPrivileged, boolean edit) {
+    private Ops getOpsRawLocked(int uid, String packageName, @Nullable String featureId,
+            boolean isPrivileged, boolean edit) {
         UidState uidState = getUidStateLocked(uid, edit);
         if (uidState == null) {
             return null;
@@ -3000,6 +3331,9 @@
             ops = new Ops(packageName, uidState, isPrivileged);
             uidState.pkgOps.put(packageName, ops);
         }
+        if (edit && featureId != null) {
+            ops.knownFeatureIds.add(featureId);
+        }
         return ops;
     }
 
@@ -3010,13 +3344,14 @@
      *
      * @param uid The uid the of the package
      * @param packageName The package name for which to get the state for
+     * @param featureId The feature in the package
      * @param edit Iff {@code true} create the {@link Ops} object if not yet created
      * @param isPrivileged Whether the package is privileged or not
      *
      * @return The {@link Ops state} of all ops for the package
      */
     private @Nullable Ops getOpsRawNoVerifyLocked(int uid, @NonNull String packageName,
-            boolean edit, boolean isPrivileged) {
+            @Nullable String featureId, boolean edit, boolean isPrivileged) {
         UidState uidState = getUidStateLocked(uid, edit);
         if (uidState == null) {
             return null;
@@ -3037,6 +3372,11 @@
             ops = new Ops(packageName, uidState, isPrivileged);
             uidState.pkgOps.put(packageName, ops);
         }
+
+        if (edit && featureId != null) {
+            ops.knownFeatureIds.add(featureId);
+        }
+
         return ops;
     }
 
@@ -3062,6 +3402,7 @@
      * @param code The code of the op
      * @param uid The uid the of the package
      * @param packageName The package name for which to get the state for
+     * @param featureId The feature in the package
      * @param isPrivileged Whether the package is privileged or not (only used if {@code edit
      *                     == true})
      * @param edit Iff {@code true} create the {@link Op} object if not yet created
@@ -3069,21 +3410,21 @@
      * @return The {@link Op state} of the op
      */
     private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName,
-            boolean isPrivileged, boolean edit) {
-        Ops ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged);
+            @Nullable String featureId, boolean isPrivileged, boolean edit) {
+        Ops ops = getOpsRawNoVerifyLocked(uid, packageName, featureId, edit, isPrivileged);
         if (ops == null) {
             return null;
         }
-        return getOpLocked(ops, code, edit);
+        return getOpLocked(ops, code, uid, edit);
     }
 
-    private Op getOpLocked(Ops ops, int code, boolean edit) {
+    private Op getOpLocked(Ops ops, int code, int uid, boolean edit) {
         Op op = ops.get(code);
         if (op == null) {
             if (!edit) {
                 return null;
             }
-            op = new Op(ops.uidState, ops.packageName, code, ops.uidState.uid);
+            op = new Op(ops.uidState, ops.packageName, code, uid);
             ops.put(code, op);
         }
         if (edit) {
@@ -3101,7 +3442,7 @@
     }
 
     private boolean isOpRestrictedLocked(int uid, int code, String packageName,
-            boolean isPrivileged) {
+            @Nullable String featureId, boolean isPrivileged) {
         int userHandle = UserHandle.getUserId(uid);
         final int restrictionSetCount = mOpUserRestrictions.size();
 
@@ -3113,7 +3454,7 @@
                 if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
                     // If we are the system, bypass user restrictions for certain codes
                     synchronized (this) {
-                        Ops ops = getOpsRawLocked(uid, packageName, isPrivileged,
+                        Ops ops = getOpsRawLocked(uid, packageName, featureId, isPrivileged,
                                 true /* edit */);
                         if ((ops != null) && ops.isPrivileged) {
                             return false;
@@ -3490,7 +3831,7 @@
                         out.startTag(null, "uid");
                         out.attribute(null, "n", Integer.toString(pkg.getUid()));
                         synchronized (this) {
-                            Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(),
+                            Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), null,
                                     false /* isPrivileged */, false /* edit */);
                             // Should always be present as the list of PackageOps is generated
                             // from Ops.
@@ -4056,7 +4397,8 @@
 
                     if (shell.packageName != null) {
                         shell.mInterface.startOperation(shell.mToken, shell.op, shell.packageUid,
-                                shell.packageName, shell.featureId, true);
+                                shell.packageName, shell.featureId, true, true,
+                                "appops start shell command");
                     } else {
                         return -1;
                     }
@@ -4200,7 +4542,7 @@
             for (int i = 0; i < numInProgressEvents; i++) {
                 InProgressStartOpEvent event = featureOp.mInProgressEvents.valueAt(i);
 
-                earliestElapsedTime = Math.min(earliestElapsedTime, event.startElapsedTime);
+                earliestElapsedTime = Math.min(earliestElapsedTime, event.getStartElapsedTime());
                 maxNumStarts = Math.max(maxNumStarts, event.numUnfinishedStarts);
             }
 
@@ -4708,8 +5050,8 @@
     @Override
     public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
         checkSystemUid("setUserRestrictions");
-        Preconditions.checkNotNull(restrictions);
-        Preconditions.checkNotNull(token);
+        Objects.requireNonNull(restrictions);
+        Objects.requireNonNull(token);
         for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
             String restriction = AppOpsManager.opToRestriction(i);
             if (restriction != null) {
@@ -4736,7 +5078,7 @@
             }
         }
         verifyIncomingOp(code);
-        Preconditions.checkNotNull(token);
+        Objects.requireNonNull(token);
         setUserRestrictionNoCheck(code, restricted, token, userHandle, exceptionPackages);
     }
 
@@ -4807,7 +5149,7 @@
         }
         // TODO moltmann: Allow to check for feature op activeness
         synchronized (AppOpsService.this) {
-            Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false, false);
+            Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, null, false, false);
             if (pkgOps == null) {
                 return false;
             }
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index fc67e24..5ac5b29 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -67,6 +67,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.Objects;
 
 /**
  * An attention service implementation that runs in System Server process.
@@ -120,7 +121,7 @@
     AttentionManagerService(Context context, PowerManager powerManager, Object lock,
             AttentionHandler handler) {
         super(context);
-        mContext = Preconditions.checkNotNull(context);
+        mContext = Objects.requireNonNull(context);
         mPowerManager = powerManager;
         mLock = lock;
         mAttentionHandler = handler;
@@ -200,7 +201,7 @@
      */
     @VisibleForTesting
     boolean checkAttention(long timeout, AttentionCallbackInternal callbackInternal) {
-        Preconditions.checkNotNull(callbackInternal);
+        Objects.requireNonNull(callbackInternal);
 
         if (!isAttentionServiceSupported()) {
             Slog.w(LOG_TAG, "Trying to call checkAttention() on an unsupported device.");
@@ -543,9 +544,9 @@
         UserState(int userId, Context context, Object lock, Handler handler,
                 ComponentName componentName) {
             mUserId = userId;
-            mContext = Preconditions.checkNotNull(context);
-            mLock = Preconditions.checkNotNull(lock);
-            mComponentName = Preconditions.checkNotNull(componentName);
+            mContext = Objects.requireNonNull(context);
+            mLock = Objects.requireNonNull(lock);
+            mComponentName = Objects.requireNonNull(componentName);
             mAttentionHandler = handler;
         }
 
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 114aac9..bc4dc8f 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -2196,7 +2196,7 @@
     public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags,
                                             String callingPackage) {
         enforceModifyAudioRoutingPermission();
-        Preconditions.checkNotNull(attr, "attr must not be null");
+        Objects.requireNonNull(attr, "attr must not be null");
         // @todo not hold the caller context, post message
         int stream = AudioProductStrategy.getLegacyStreamTypeForStrategyWithAudioAttributes(attr);
         final int device = getDeviceForStream(stream);
@@ -2231,7 +2231,7 @@
     /** @see AudioManager#getVolumeIndexForAttributes(attr) */
     public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
         enforceModifyAudioRoutingPermission();
-        Preconditions.checkNotNull(attr, "attr must not be null");
+        Objects.requireNonNull(attr, "attr must not be null");
         int stream = AudioProductStrategy.getLegacyStreamTypeForStrategyWithAudioAttributes(attr);
         final int device = getDeviceForStream(stream);
 
@@ -2241,14 +2241,14 @@
     /** @see AudioManager#getMaxVolumeIndexForAttributes(attr) */
     public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
         enforceModifyAudioRoutingPermission();
-        Preconditions.checkNotNull(attr, "attr must not be null");
+        Objects.requireNonNull(attr, "attr must not be null");
         return AudioSystem.getMaxVolumeIndexForAttributes(attr);
     }
 
     /** @see AudioManager#getMinVolumeIndexForAttributes(attr) */
     public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
         enforceModifyAudioRoutingPermission();
-        Preconditions.checkNotNull(attr, "attr must not be null");
+        Objects.requireNonNull(attr, "attr must not be null");
         return AudioSystem.getMinVolumeIndexForAttributes(attr);
     }
 
@@ -2510,7 +2510,7 @@
 
 
     private int getVolumeGroupIdForAttributes(@NonNull AudioAttributes attributes) {
-        Preconditions.checkNotNull(attributes, "attributes must not be null");
+        Objects.requireNonNull(attributes, "attributes must not be null");
         int volumeGroupId = getVolumeGroupIdForAttributesInt(attributes);
         if (volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
             return volumeGroupId;
@@ -2521,7 +2521,7 @@
     }
 
     private int getVolumeGroupIdForAttributesInt(@NonNull AudioAttributes attributes) {
-        Preconditions.checkNotNull(attributes, "attributes must not be null");
+        Objects.requireNonNull(attributes, "attributes must not be null");
         for (final AudioProductStrategy productStrategy :
                 AudioProductStrategy.getAudioProductStrategies()) {
             int volumeGroupId = productStrategy.getVolumeGroupIdForAudioAttributes(attributes);
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index ff0b015..28f67fe 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -34,6 +34,7 @@
 
 import java.io.PrintWriter;
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * A utility to map from an ambient brightness to a display's "backlight" brightness based on the
@@ -702,7 +703,7 @@
                     "Nits and backlight arrays must not be empty!");
             Preconditions.checkArgument(nits.length == backlight.length,
                     "Nits and backlight arrays must be the same length!");
-            Preconditions.checkNotNull(config);
+            Objects.requireNonNull(config);
             Preconditions.checkArrayElementsInRange(nits, 0, Float.MAX_VALUE, "nits");
             Preconditions.checkArrayElementsInRange(backlight,
                     PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON, "backlight");
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index eebc738..cf94d46 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -37,6 +37,7 @@
 import android.view.Surface;
 import android.view.SurfaceControl;
 
+import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.LocalServices;
 import com.android.server.lights.Light;
 import com.android.server.lights.LightsManager;
@@ -641,9 +642,7 @@
 
         @Override
         public void setRequestedColorModeLocked(int colorMode) {
-            if (requestColorModeLocked(colorMode)) {
-                updateDeviceInfoLocked();
-            }
+            requestColorModeLocked(colorMode);
         }
 
         @Override
@@ -671,12 +670,22 @@
             if (mDisplayModeSpecsInvalid || !displayModeSpecs.equals(mDisplayModeSpecs)) {
                 mDisplayModeSpecsInvalid = false;
                 mDisplayModeSpecs.copyFrom(displayModeSpecs);
-                final IBinder token = getDisplayTokenLocked();
-                SurfaceControl.setDesiredDisplayConfigSpecs(token,
+                getHandler().sendMessage(PooledLambda.obtainMessage(
+                        LocalDisplayDevice::setDesiredDisplayModeSpecsAsync, this,
+                        getDisplayTokenLocked(),
                         new SurfaceControl.DesiredDisplayConfigSpecs(defaultPhysIndex,
                                 mDisplayModeSpecs.refreshRateRange.min,
-                                mDisplayModeSpecs.refreshRateRange.max));
-                int activePhysIndex = SurfaceControl.getActiveConfig(token);
+                                mDisplayModeSpecs.refreshRateRange.max)));
+            }
+        }
+
+        private void setDesiredDisplayModeSpecsAsync(IBinder displayToken,
+                SurfaceControl.DesiredDisplayConfigSpecs configSpecs) {
+            // Do not lock when calling these SurfaceControl methods because they are sync
+            // operations that may block for a while when setting display power mode.
+            SurfaceControl.setDesiredDisplayConfigSpecs(displayToken, configSpecs);
+            final int activePhysIndex = SurfaceControl.getActiveConfig(displayToken);
+            synchronized (getSyncRoot()) {
                 if (updateActiveModeLocked(activePhysIndex)) {
                     updateDeviceInfoLocked();
                 }
@@ -708,19 +717,30 @@
             return true;
         }
 
-        public boolean requestColorModeLocked(int colorMode) {
+        public void requestColorModeLocked(int colorMode) {
             if (mActiveColorMode == colorMode) {
-                return false;
+                return;
             }
             if (!mSupportedColorModes.contains(colorMode)) {
                 Slog.w(TAG, "Unable to find color mode " + colorMode
                         + ", ignoring request.");
-                return false;
+                return;
             }
-            SurfaceControl.setActiveColorMode(getDisplayTokenLocked(), colorMode);
+
             mActiveColorMode = colorMode;
             mActiveColorModeInvalid = false;
-            return true;
+            getHandler().sendMessage(PooledLambda.obtainMessage(
+                    LocalDisplayDevice::requestColorModeAsync, this,
+                    getDisplayTokenLocked(), colorMode));
+        }
+
+        private void requestColorModeAsync(IBinder displayToken, int colorMode) {
+            // Do not lock when calling this SurfaceControl method because it is a sync operation
+            // that may block for a while when setting display power mode.
+            SurfaceControl.setActiveColorMode(displayToken, colorMode);
+            synchronized (getSyncRoot()) {
+                updateDeviceInfoLocked();
+            }
         }
 
         @Override
diff --git a/services/core/java/com/android/server/display/whitebalance/AmbientSensor.java b/services/core/java/com/android/server/display/whitebalance/AmbientSensor.java
index 1707a62..75d00ff 100644
--- a/services/core/java/com/android/server/display/whitebalance/AmbientSensor.java
+++ b/services/core/java/com/android/server/display/whitebalance/AmbientSensor.java
@@ -29,6 +29,7 @@
 import com.android.server.display.utils.History;
 
 import java.io.PrintWriter;
+import java.util.Objects;
 
 /**
  * The DisplayWhiteBalanceController uses the AmbientSensor to detect changes in the ambient
@@ -139,8 +140,8 @@
 
 
     private static void validateArguments(Handler handler, SensorManager sensorManager, int rate) {
-        Preconditions.checkNotNull(handler, "handler cannot be null");
-        Preconditions.checkNotNull(sensorManager, "sensorManager cannot be null");
+        Objects.requireNonNull(handler, "handler cannot be null");
+        Objects.requireNonNull(sensorManager, "sensorManager cannot be null");
         if (rate <= 0) {
             throw new IllegalArgumentException("rate must be positive");
         }
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
index 88a7077..d64fcbc 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
@@ -28,6 +28,7 @@
 import com.android.server.display.utils.History;
 
 import java.io.PrintWriter;
+import java.util.Objects;
 
 /**
  * The DisplayWhiteBalanceController drives display white-balance (automatically correcting the
@@ -475,13 +476,13 @@
             AmbientSensor.AmbientColorTemperatureSensor colorTemperatureSensor,
             AmbientFilter colorTemperatureFilter,
             DisplayWhiteBalanceThrottler throttler) {
-        Preconditions.checkNotNull(brightnessSensor, "brightnessSensor must not be null");
-        Preconditions.checkNotNull(brightnessFilter, "brightnessFilter must not be null");
-        Preconditions.checkNotNull(colorTemperatureSensor,
+        Objects.requireNonNull(brightnessSensor, "brightnessSensor must not be null");
+        Objects.requireNonNull(brightnessFilter, "brightnessFilter must not be null");
+        Objects.requireNonNull(colorTemperatureSensor,
                 "colorTemperatureSensor must not be null");
-        Preconditions.checkNotNull(colorTemperatureFilter,
+        Objects.requireNonNull(colorTemperatureFilter,
                 "colorTemperatureFilter must not be null");
-        Preconditions.checkNotNull(throttler, "throttler cannot be null");
+        Objects.requireNonNull(throttler, "throttler cannot be null");
     }
 
     private boolean enable() {
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceSettings.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceSettings.java
index 6e78894..0efb749 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceSettings.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceSettings.java
@@ -30,6 +30,7 @@
 import com.android.server.display.whitebalance.DisplayWhiteBalanceController.Callbacks;
 
 import java.io.PrintWriter;
+import java.util.Objects;
 
 /**
  * The DisplayWhiteBalanceSettings holds the state of all the settings related to
@@ -144,8 +145,8 @@
     }
 
     private void validateArguments(Context context, Handler handler) {
-        Preconditions.checkNotNull(context, "context must not be null");
-        Preconditions.checkNotNull(handler, "handler must not be null");
+        Objects.requireNonNull(context, "context must not be null");
+        Objects.requireNonNull(handler, "handler must not be null");
     }
 
     private void setEnabled(boolean enabled) {
diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
index 080e6ce..a9e8719 100755
--- a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
@@ -26,6 +26,7 @@
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Feature action that handles device discovery sequences.
@@ -106,7 +107,7 @@
      */
     DeviceDiscoveryAction(HdmiCecLocalDevice source, DeviceDiscoveryCallback callback, int delay) {
         super(source);
-        mCallback = Preconditions.checkNotNull(callback);
+        mCallback = Objects.requireNonNull(callback);
         mDelayPeriod = delay;
     }
 
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index 58f6ba2..c58000f 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -50,6 +50,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Base class for {@link SystemService SystemServices} that support multi user.
@@ -373,7 +374,7 @@
                 + durationMs + "ms");
         enforceCallingPermissionForManagement();
 
-        Preconditions.checkNotNull(componentName);
+        Objects.requireNonNull(componentName);
         final int maxDurationMs = getMaximumTemporaryServiceDurationMs();
         if (durationMs > maxDurationMs) {
             throw new IllegalArgumentException(
@@ -735,7 +736,7 @@
      * @throws SecurityException when it's not...
      */
     protected final void assertCalledByPackageOwner(@NonNull String packageName) {
-        Preconditions.checkNotNull(packageName);
+        Objects.requireNonNull(packageName);
         final int uid = Binder.getCallingUid();
         final String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
         if (packages != null) {
@@ -954,6 +955,35 @@
                 onServicePackageRestartedLocked(userId);
             }
 
+            @Override
+            public void onPackageModified(String packageName) {
+                if (verbose) Slog.v(mTag, "onPackageModified(): " + packageName);
+
+                final int userId = getChangingUserId();
+                final String serviceName = mServiceNameResolver.getDefaultServiceName(userId);
+                if (serviceName == null) {
+                    return;
+                }
+
+                final ComponentName serviceComponentName =
+                        ComponentName.unflattenFromString(serviceName);
+                if (serviceComponentName == null
+                        || !serviceComponentName.getPackageName().equals(packageName)) {
+                    return;
+                }
+
+                // The default service package has changed, update the cached if the service
+                // exists but no active component.
+                final S service = peekServiceForUserLocked(userId);
+                if (service != null) {
+                    final ComponentName componentName = service.getServiceComponentName();
+                    if (componentName == null) {
+                        if (verbose) Slog.v(mTag, "update cached");
+                        updateCachedServiceLocked(userId);
+                    }
+                }
+            }
+
             private String getActiveServicePackageNameLocked() {
                 final int userId = getChangingUserId();
                 final S service = peekServiceForUserLocked(userId);
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index bf73aa3..ae6d63a 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1719,7 +1719,7 @@
     // Binder call
     @Override
     public void setCustomPointerIcon(PointerIcon icon) {
-        Preconditions.checkNotNull(icon);
+        Objects.requireNonNull(icon);
         nativeSetCustomPointerIcon(mPtr, icon);
     }
 
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index 44c8971..c40e8af 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -19,8 +19,6 @@
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
 import android.content.ComponentName;
-import android.os.RemoteException;
-import android.util.Log;
 import android.view.autofill.AutofillId;
 import android.view.inputmethod.InlineSuggestionsRequest;
 import android.view.inputmethod.InputMethodInfo;
@@ -99,12 +97,6 @@
                 @Override
                 public void onCreateInlineSuggestionsRequest(ComponentName componentName,
                         AutofillId autofillId, IInlineSuggestionsRequestCallback cb) {
-                    try {
-                        cb.onInlineSuggestionsUnsupported();
-                    } catch (RemoteException e) {
-                        Log.w("IMManagerInternal", "RemoteException calling"
-                                + " onInlineSuggestionsUnsupported: " + e);
-                    }
                 }
             };
 
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 5865dc4..8b6b614 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1792,10 +1792,18 @@
     @GuardedBy("mMethodMap")
     private void onCreateInlineSuggestionsRequestLocked(ComponentName componentName,
             AutofillId autofillId, IInlineSuggestionsRequestCallback callback) {
-        if (mCurMethod != null) {
-            executeOrSendMessage(mCurMethod,
-                    mCaller.obtainMessageOOOO(MSG_INLINE_SUGGESTIONS_REQUEST, mCurMethod,
-                            componentName, autofillId, callback));
+
+        final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
+        try {
+            if (imi != null && imi.isInlineSuggestionsEnabled() && mCurMethod != null) {
+                executeOrSendMessage(mCurMethod,
+                        mCaller.obtainMessageOOOO(MSG_INLINE_SUGGESTIONS_REQUEST, mCurMethod,
+                                componentName, autofillId, callback));
+            } else {
+                callback.onInlineSuggestionsUnsupported();
+            }
+        } catch (RemoteException e) {
+            Slog.w(TAG, "RemoteException calling onCreateInlineSuggestionsRequest(): " + e);
         }
     }
 
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index c13d55a..1f9379c 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -59,7 +59,6 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.InputChannel;
@@ -198,8 +197,7 @@
                                 //TODO(b/137800469): support multi client IMEs.
                                 cb.onInlineSuggestionsUnsupported();
                             } catch (RemoteException e) {
-                                Log.w("MultiClientIMManager", "RemoteException calling"
-                                        + " onInlineSuggestionsUnsupported: " + e);
+                                Slog.w(TAG, "Failed to call onInlineSuggestionsUnsupported.", e);
                             }
                         }
                     });
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index 33e12c6..b1639a9 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -385,6 +385,9 @@
                         String packageName = getPackageNameNormalized(packageAndCert[0]);
                         String cert = packageAndCert[1];
                         packageCertMap.put(packageName, cert);
+                    } else if (packageAndCert.length == 1
+                            && packageAndCert[0].equals(ADB_INSTALLER)) {
+                        packageCertMap.put(ADB_INSTALLER, INSTALLER_CERT_NOT_APPLICABLE);
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/location/RemoteListenerHelper.java b/services/core/java/com/android/server/location/RemoteListenerHelper.java
index 60ce1f4..01522739 100644
--- a/services/core/java/com/android/server/location/RemoteListenerHelper.java
+++ b/services/core/java/com/android/server/location/RemoteListenerHelper.java
@@ -25,10 +25,9 @@
 import android.os.RemoteException;
 import android.util.Log;
 
-import com.android.internal.util.Preconditions;
-
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * A helper class that handles operations in remote listeners.
@@ -61,7 +60,7 @@
     private int mLastReportedResult = RESULT_UNKNOWN;
 
     protected RemoteListenerHelper(Context context, Handler handler, String name) {
-        Preconditions.checkNotNull(name);
+        Objects.requireNonNull(name);
         mHandler = handler;
         mTag = name;
         mContext = context;
@@ -77,7 +76,7 @@
      * Adds GNSS data listener {@code listener} with caller identify {@code callerIdentify}.
      */
     public void addListener(@NonNull TListener listener, CallerIdentity callerIdentity) {
-        Preconditions.checkNotNull(listener, "Attempted to register a 'null' listener.");
+        Objects.requireNonNull(listener, "Attempted to register a 'null' listener.");
         IBinder binder = listener.asBinder();
         synchronized (mListenerMap) {
             if (mListenerMap.containsKey(binder)) {
@@ -116,7 +115,7 @@
      * Remove GNSS data listener {@code listener}.
      */
     public void removeListener(@NonNull TListener listener) {
-        Preconditions.checkNotNull(listener, "Attempted to remove a 'null' listener.");
+        Objects.requireNonNull(listener, "Attempted to remove a 'null' listener.");
         synchronized (mListenerMap) {
             mListenerMap.remove(listener.asBinder());
             if (mListenerMap.isEmpty()) {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index bcc4c1f..6c65c36 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -151,6 +151,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -1594,8 +1595,8 @@
      */
     private boolean setLockCredentialInternal(LockscreenCredential credential,
             LockscreenCredential savedCredential, int userId, boolean isLockTiedToParent) {
-        Preconditions.checkNotNull(credential);
-        Preconditions.checkNotNull(savedCredential);
+        Objects.requireNonNull(credential);
+        Objects.requireNonNull(savedCredential);
         synchronized (mSpManager) {
             if (isSyntheticPasswordBasedCredentialLocked(userId)) {
                 return spBasedSetLockCredentialInternalLocked(credential, savedCredential, userId,
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index c53647d..0fe16be 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -57,6 +57,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Objects;
 import java.util.Set;
 
 
@@ -228,8 +229,8 @@
          * by {@link #setEscrowData} before calling this.
          */
         public void recreateFromEscrow(byte[] escrowSplit0) {
-            Preconditions.checkNotNull(mEscrowSplit1);
-            Preconditions.checkNotNull(mEncryptedEscrowSplit0);
+            Objects.requireNonNull(mEscrowSplit1);
+            Objects.requireNonNull(mEncryptedEscrowSplit0);
             recreate(escrowSplit0, mEscrowSplit1);
         }
 
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 1b14ce2..383d5cf 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -75,6 +75,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
@@ -302,8 +303,8 @@
         checkRecoverKeyStorePermission();
         rootCertificateAlias =
                 mTestCertHelper.getDefaultCertificateAliasIfEmpty(rootCertificateAlias);
-        Preconditions.checkNotNull(recoveryServiceCertFile, "recoveryServiceCertFile is null");
-        Preconditions.checkNotNull(recoveryServiceSigFile, "recoveryServiceSigFile is null");
+        Objects.requireNonNull(recoveryServiceCertFile, "recoveryServiceCertFile is null");
+        Objects.requireNonNull(recoveryServiceSigFile, "recoveryServiceSigFile is null");
 
         SigXml sigXml;
         try {
@@ -393,7 +394,7 @@
      */
     public void setRecoveryStatus(@NonNull String alias, int status) throws RemoteException {
         checkRecoverKeyStorePermission();
-        Preconditions.checkNotNull(alias, "alias is null");
+        Objects.requireNonNull(alias, "alias is null");
         long updatedRows = mDatabase.setRecoveryStatus(Binder.getCallingUid(), alias, status);
         if (updatedRows < 0) {
             throw new ServiceSpecificException(
@@ -424,7 +425,7 @@
             @NonNull @KeyChainProtectionParams.UserSecretType int[] secretTypes)
             throws RemoteException {
         checkRecoverKeyStorePermission();
-        Preconditions.checkNotNull(secretTypes, "secretTypes is null");
+        Objects.requireNonNull(secretTypes, "secretTypes is null");
         int userId = UserHandle.getCallingUserId();
         int uid = Binder.getCallingUid();
 
@@ -556,11 +557,11 @@
         checkRecoverKeyStorePermission();
         rootCertificateAlias =
                 mTestCertHelper.getDefaultCertificateAliasIfEmpty(rootCertificateAlias);
-        Preconditions.checkNotNull(sessionId, "invalid session");
-        Preconditions.checkNotNull(verifierCertPath, "verifierCertPath is null");
-        Preconditions.checkNotNull(vaultParams, "vaultParams is null");
-        Preconditions.checkNotNull(vaultChallenge, "vaultChallenge is null");
-        Preconditions.checkNotNull(secrets, "secrets is null");
+        Objects.requireNonNull(sessionId, "invalid session");
+        Objects.requireNonNull(verifierCertPath, "verifierCertPath is null");
+        Objects.requireNonNull(vaultParams, "vaultParams is null");
+        Objects.requireNonNull(vaultChallenge, "vaultChallenge is null");
+        Objects.requireNonNull(secrets, "secrets is null");
         CertPath certPath;
         try {
             certPath = verifierCertPath.getCertPath();
@@ -666,13 +667,13 @@
      */
     public void closeSession(@NonNull String sessionId) throws RemoteException {
         checkRecoverKeyStorePermission();
-        Preconditions.checkNotNull(sessionId, "invalid session");
+        Objects.requireNonNull(sessionId, "invalid session");
         mRecoverySessionStorage.remove(Binder.getCallingUid(), sessionId);
     }
 
     public void removeKey(@NonNull String alias) throws RemoteException {
         checkRecoverKeyStorePermission();
-        Preconditions.checkNotNull(alias, "alias is null");
+        Objects.requireNonNull(alias, "alias is null");
         int uid = Binder.getCallingUid();
         int userId = UserHandle.getCallingUserId();
 
@@ -711,7 +712,7 @@
     public String generateKeyWithMetadata(@NonNull String alias, @Nullable byte[] metadata)
             throws RemoteException {
         checkRecoverKeyStorePermission();
-        Preconditions.checkNotNull(alias, "alias is null");
+        Objects.requireNonNull(alias, "alias is null");
         int uid = Binder.getCallingUid();
         int userId = UserHandle.getCallingUserId();
 
@@ -771,8 +772,8 @@
     public @Nullable String importKeyWithMetadata(@NonNull String alias, @NonNull byte[] keyBytes,
             @Nullable byte[] metadata) throws RemoteException {
         checkRecoverKeyStorePermission();
-        Preconditions.checkNotNull(alias, "alias is null");
-        Preconditions.checkNotNull(keyBytes, "keyBytes is null");
+        Objects.requireNonNull(alias, "alias is null");
+        Objects.requireNonNull(keyBytes, "keyBytes is null");
         if (keyBytes.length != RecoverableKeyGenerator.KEY_SIZE_BITS / Byte.SIZE) {
             Log.e(TAG, "The given key for import doesn't have the required length "
                     + RecoverableKeyGenerator.KEY_SIZE_BITS);
@@ -816,7 +817,7 @@
      */
     public @Nullable String getKey(@NonNull String alias) throws RemoteException {
         checkRecoverKeyStorePermission();
-        Preconditions.checkNotNull(alias, "alias is null");
+        Objects.requireNonNull(alias, "alias is null");
         int uid = Binder.getCallingUid();
         int userId = UserHandle.getCallingUserId();
         return getAlias(userId, uid, alias);
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 4cb41da..ef8f647 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -45,12 +45,12 @@
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnProfile;
 import com.android.internal.notification.SystemNotificationChannels;
-import com.android.internal.util.Preconditions;
 import com.android.server.ConnectivityService;
 import com.android.server.EventLogTags;
 import com.android.server.connectivity.Vpn;
 
 import java.util.List;
+import java.util.Objects;
 
 /**
  * State tracker for lockdown mode. Watches for normal {@link NetworkInfo} to be
@@ -90,11 +90,11 @@
             @NonNull Handler handler,
             @NonNull Vpn vpn,
             @NonNull VpnProfile profile) {
-        mContext = Preconditions.checkNotNull(context);
-        mConnService = Preconditions.checkNotNull(connService);
-        mHandler = Preconditions.checkNotNull(handler);
-        mVpn = Preconditions.checkNotNull(vpn);
-        mProfile = Preconditions.checkNotNull(profile);
+        mContext = Objects.requireNonNull(context);
+        mConnService = Objects.requireNonNull(connService);
+        mHandler = Objects.requireNonNull(handler);
+        mVpn = Objects.requireNonNull(vpn);
+        mProfile = Objects.requireNonNull(profile);
 
         final Intent configIntent = new Intent(ACTION_VPN_SETTINGS);
         mConfigIntent = PendingIntent.getActivity(mContext, 0, configIntent, 0);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 99562eb..2390da5e 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -91,7 +91,6 @@
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
 import static com.android.internal.util.ArrayUtils.appendInt;
-import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
 import static com.android.internal.util.XmlUtils.readIntAttribute;
 import static com.android.internal.util.XmlUtils.readLongAttribute;
@@ -614,12 +613,12 @@
     public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
             INetworkManagementService networkManagement, IPackageManager pm, Clock clock,
             File systemDir, boolean suppressDefaultPolicy) {
-        mContext = checkNotNull(context, "missing context");
-        mActivityManager = checkNotNull(activityManager, "missing activityManager");
-        mNetworkManager = checkNotNull(networkManagement, "missing networkManagement");
+        mContext = Objects.requireNonNull(context, "missing context");
+        mActivityManager = Objects.requireNonNull(activityManager, "missing activityManager");
+        mNetworkManager = Objects.requireNonNull(networkManagement, "missing networkManagement");
         mDeviceIdleController = IDeviceIdleController.Stub.asInterface(ServiceManager.getService(
                 Context.DEVICE_IDLE_CONTROLLER));
-        mClock = checkNotNull(clock, "missing Clock");
+        mClock = Objects.requireNonNull(clock, "missing Clock");
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
         mIPm = pm;
@@ -646,7 +645,7 @@
     }
 
     public void bindConnectivityManager(IConnectivityManager connManager) {
-        mConnManager = checkNotNull(connManager, "missing IConnectivityManager");
+        mConnManager = Objects.requireNonNull(connManager, "missing IConnectivityManager");
     }
 
     @GuardedBy("mUidRulesFirstLock")
@@ -3106,17 +3105,16 @@
             return;
         }
 
-        long applicableNetworkTypes = 0;
+        final ArraySet<Integer> applicableNetworkTypes = new ArraySet<Integer>();
         boolean allNetworks = false;
         for (SubscriptionPlan plan : plans) {
             if (plan.getNetworkTypes() == null) {
                 allNetworks = true;
             } else {
-                if ((applicableNetworkTypes & plan.getNetworkTypesBitMask()) != 0) {
+                final int[] networkTypes = plan.getNetworkTypes();
+                if (!addAll(applicableNetworkTypes, networkTypes)) {
                     throw new IllegalArgumentException(
                             "Multiple subscription plans defined for a single network type.");
-                } else {
-                    applicableNetworkTypes |= plan.getNetworkTypesBitMask();
                 }
             }
         }
@@ -3128,6 +3126,19 @@
         }
     }
 
+    /**
+     * Adds all of the {@code elements} to the {@code set}.
+     *
+     * @return {@code false} if any element is not added because the set already have the value.
+     */
+    private static boolean addAll(@NonNull Set<Integer> set, @NonNull int... elements) {
+        boolean result = true;
+        for (int element : elements) {
+            result &= set.add(element);
+        }
+        return result;
+    }
+
     @Override
     public SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage) {
         enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage);
@@ -3295,7 +3306,7 @@
         enforceSubscriptionPlanValidity(plans);
 
         for (SubscriptionPlan plan : plans) {
-            Preconditions.checkNotNull(plan);
+            Objects.requireNonNull(plan);
         }
 
         final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
index 6af962b..9eff5d1 100644
--- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
@@ -21,8 +21,6 @@
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.text.format.DateUtils.YEAR_IN_MILLIS;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 import android.net.NetworkStats;
 import android.net.NetworkStats.NonMonotonicObserver;
 import android.net.NetworkStatsHistory;
@@ -54,6 +52,7 @@
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * Logic to record deltas between periodic {@link NetworkStats} snapshots into
@@ -116,9 +115,9 @@
      */
     public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver<String> observer,
             DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags) {
-        mRotator = checkNotNull(rotator, "missing FileRotator");
-        mObserver = checkNotNull(observer, "missing NonMonotonicObserver");
-        mDropBox = checkNotNull(dropBox, "missing DropBoxManager");
+        mRotator = Objects.requireNonNull(rotator, "missing FileRotator");
+        mObserver = Objects.requireNonNull(observer, "missing NonMonotonicObserver");
+        mDropBox = Objects.requireNonNull(dropBox, "missing DropBoxManager");
         mCookie = cookie;
 
         mBucketDuration = bucketDuration;
@@ -165,7 +164,7 @@
      * as reference is valid.
      */
     public NetworkStatsCollection getOrLoadCompleteLocked() {
-        checkNotNull(mRotator, "missing FileRotator");
+        Objects.requireNonNull(mRotator, "missing FileRotator");
         NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
         if (res == null) {
             res = loadLocked(Long.MIN_VALUE, Long.MAX_VALUE);
@@ -175,7 +174,7 @@
     }
 
     public NetworkStatsCollection getOrLoadPartialLocked(long start, long end) {
-        checkNotNull(mRotator, "missing FileRotator");
+        Objects.requireNonNull(mRotator, "missing FileRotator");
         NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
         if (res == null) {
             res = loadLocked(start, end);
@@ -280,7 +279,7 @@
      * {@link #mPersistThresholdBytes}.
      */
     public void maybePersistLocked(long currentTimeMillis) {
-        checkNotNull(mRotator, "missing FileRotator");
+        Objects.requireNonNull(mRotator, "missing FileRotator");
         final long pendingBytes = mPending.getTotalBytes();
         if (pendingBytes >= mPersistThresholdBytes) {
             forcePersistLocked(currentTimeMillis);
@@ -293,7 +292,7 @@
      * Force persisting any pending deltas.
      */
     public void forcePersistLocked(long currentTimeMillis) {
-        checkNotNull(mRotator, "missing FileRotator");
+        Objects.requireNonNull(mRotator, "missing FileRotator");
         if (mPending.isDirty()) {
             if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie);
             try {
@@ -356,7 +355,7 @@
         private final NetworkStatsCollection mCollection;
 
         public CombiningRewriter(NetworkStatsCollection collection) {
-            mCollection = checkNotNull(collection, "missing NetworkStatsCollection");
+            mCollection = Objects.requireNonNull(collection, "missing NetworkStatsCollection");
         }
 
         @Override
@@ -418,7 +417,7 @@
     }
 
     public void importLegacyNetworkLocked(File file) throws IOException {
-        checkNotNull(mRotator, "missing FileRotator");
+        Objects.requireNonNull(mRotator, "missing FileRotator");
 
         // legacy file still exists; start empty to avoid double importing
         mRotator.deleteAll();
@@ -438,7 +437,7 @@
     }
 
     public void importLegacyUidLocked(File file) throws IOException {
-        checkNotNull(mRotator, "missing FileRotator");
+        Objects.requireNonNull(mRotator, "missing FileRotator");
 
         // legacy file still exists; start empty to avoid double importing
         mRotator.deleteAll();
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 0288f0c..ec8a8e7 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -65,7 +65,6 @@
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 import static android.text.format.DateUtils.SECOND_IN_MILLIS;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
 import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
 import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet;
@@ -148,6 +147,7 @@
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Collect and persist detailed network statistics, and provide this data to
@@ -357,17 +357,18 @@
             TelephonyManager teleManager, NetworkStatsSettings settings,
             NetworkStatsFactory factory, NetworkStatsObservers statsObservers, File systemDir,
             File baseDir) {
-        mContext = checkNotNull(context, "missing Context");
-        mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService");
-        mAlarmManager = checkNotNull(alarmManager, "missing AlarmManager");
-        mClock = checkNotNull(clock, "missing Clock");
-        mSettings = checkNotNull(settings, "missing NetworkStatsSettings");
-        mTeleManager = checkNotNull(teleManager, "missing TelephonyManager");
-        mWakeLock = checkNotNull(wakeLock, "missing WakeLock");
-        mStatsFactory = checkNotNull(factory, "missing factory");
-        mStatsObservers = checkNotNull(statsObservers, "missing NetworkStatsObservers");
-        mSystemDir = checkNotNull(systemDir, "missing systemDir");
-        mBaseDir = checkNotNull(baseDir, "missing baseDir");
+        mContext = Objects.requireNonNull(context, "missing Context");
+        mNetworkManager = Objects.requireNonNull(networkManager,
+            "missing INetworkManagementService");
+        mAlarmManager = Objects.requireNonNull(alarmManager, "missing AlarmManager");
+        mClock = Objects.requireNonNull(clock, "missing Clock");
+        mSettings = Objects.requireNonNull(settings, "missing NetworkStatsSettings");
+        mTeleManager = Objects.requireNonNull(teleManager, "missing TelephonyManager");
+        mWakeLock = Objects.requireNonNull(wakeLock, "missing WakeLock");
+        mStatsFactory = Objects.requireNonNull(factory, "missing factory");
+        mStatsObservers = Objects.requireNonNull(statsObservers, "missing NetworkStatsObservers");
+        mSystemDir = Objects.requireNonNull(systemDir, "missing systemDir");
+        mBaseDir = Objects.requireNonNull(baseDir, "missing baseDir");
         mUseBpfTrafficStats = new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists();
     }
 
@@ -896,11 +897,11 @@
     @Override
     public DataUsageRequest registerUsageCallback(String callingPackage,
                 DataUsageRequest request, Messenger messenger, IBinder binder) {
-        checkNotNull(callingPackage, "calling package is null");
-        checkNotNull(request, "DataUsageRequest is null");
-        checkNotNull(request.template, "NetworkTemplate is null");
-        checkNotNull(messenger, "messenger is null");
-        checkNotNull(binder, "binder is null");
+        Objects.requireNonNull(callingPackage, "calling package is null");
+        Objects.requireNonNull(request, "DataUsageRequest is null");
+        Objects.requireNonNull(request.template, "NetworkTemplate is null");
+        Objects.requireNonNull(messenger, "messenger is null");
+        Objects.requireNonNull(binder, "binder is null");
 
         int callingUid = Binder.getCallingUid();
         @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(callingPackage);
@@ -921,7 +922,7 @@
 
     @Override
     public void unregisterUsageRequest(DataUsageRequest request) {
-        checkNotNull(request, "DataUsageRequest is null");
+        Objects.requireNonNull(request, "DataUsageRequest is null");
 
         int callingUid = Binder.getCallingUid();
         final long token = Binder.clearCallingIdentity();
@@ -1795,7 +1796,7 @@
         private final ContentResolver mResolver;
 
         public DefaultNetworkStatsSettings(Context context) {
-            mResolver = checkNotNull(context.getContentResolver());
+            mResolver = Objects.requireNonNull(context.getContentResolver());
             // TODO: adjust these timings for production builds
         }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b793d6d..04e7372 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -11319,6 +11319,12 @@
                             "Static shared libs cannot declare permission groups");
                 }
 
+                // Static shared libs cannot declare features
+                if (pkg.getFeatures() != null && !pkg.getFeatures().isEmpty()) {
+                    throw new PackageManagerException(
+                            "Static shared libs cannot declare features");
+                }
+
                 // Static shared libs cannot declare permissions
                 if (pkg.getPermissions() != null && !pkg.getPermissions().isEmpty()) {
                     throw new PackageManagerException(
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 605f869..9cd6f16 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -3025,10 +3025,9 @@
     @Override
     public void startOneTimePermissionSession(String packageName, @UserIdInt int userId,
             long timeoutMillis, int importanceToResetTimer, int importanceToKeepSessionAlive) {
-        mContext.enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
-                "Must be able to revoke runtime permissions to register permissions as one time.");
-        mContext.enforceCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS,
-                "Must be able to access usage stats to register permissions as one time.");
+        mContext.enforceCallingPermission(Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS,
+                "Must hold " + Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS
+                        + " to register permissions as one time.");
         packageName = Preconditions.checkNotNull(packageName);
 
         long token = Binder.clearCallingIdentity();
@@ -3042,10 +3041,9 @@
 
     @Override
     public void stopOneTimePermissionSession(String packageName, @UserIdInt int userId) {
-        mContext.enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
-                "Must be able to revoke runtime permissions to remove permissions as one time.");
-        mContext.enforceCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS,
-                "Must be able to access usage stats to remove permissions as one time.");
+        mContext.enforceCallingPermission(Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS,
+                "Must hold " + Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS
+                        + " to remove permissions as one time.");
         Preconditions.checkNotNull(packageName);
 
         long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 0d8f257..5a124a7 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -48,34 +48,19 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
-import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
-import static android.view.WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_PHONE;
-import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
 import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION;
-import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
 import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
 import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
-import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
 import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
@@ -2182,52 +2167,6 @@
         }
     }
 
-    @Override
-    public boolean checkShowToOwnerOnly(WindowManager.LayoutParams attrs) {
-
-        // If this switch statement is modified, modify the comment in the declarations of
-        // the type in {@link WindowManager.LayoutParams} as well.
-        switch (attrs.type) {
-            default:
-                // These are the windows that by default are shown only to the user that created
-                // them. If this needs to be overridden, set
-                // {@link WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS} in
-                // {@link WindowManager.LayoutParams}. Note that permission
-                // {@link android.Manifest.permission.INTERNAL_SYSTEM_WINDOW} is required as well.
-                if ((attrs.privateFlags & SYSTEM_FLAG_SHOW_FOR_ALL_USERS) == 0) {
-                    return true;
-                }
-                break;
-
-            // These are the windows that by default are shown to all users. However, to
-            // protect against spoofing, check permissions below.
-            case TYPE_APPLICATION_STARTING:
-            case TYPE_BOOT_PROGRESS:
-            case TYPE_DISPLAY_OVERLAY:
-            case TYPE_INPUT_CONSUMER:
-            case TYPE_KEYGUARD_DIALOG:
-            case TYPE_MAGNIFICATION_OVERLAY:
-            case TYPE_NAVIGATION_BAR:
-            case TYPE_NAVIGATION_BAR_PANEL:
-            case TYPE_PHONE:
-            case TYPE_POINTER:
-            case TYPE_PRIORITY_PHONE:
-            case TYPE_SEARCH_BAR:
-            case TYPE_STATUS_BAR:
-            case TYPE_STATUS_BAR_PANEL:
-            case TYPE_STATUS_BAR_SUB_PANEL:
-            case TYPE_SYSTEM_DIALOG:
-            case TYPE_VOLUME_OVERLAY:
-            case TYPE_PRESENTATION:
-            case TYPE_PRIVATE_PRESENTATION:
-            case TYPE_DOCK_DIVIDER:
-                break;
-        }
-
-        // Check if third party app has set window to system window type.
-        return mContext.checkCallingOrSelfPermission(INTERNAL_SYSTEM_WINDOW) != PERMISSION_GRANTED;
-    }
-
     void readLidState() {
         mDefaultDisplayPolicy.setLidState(mWindowManagerFuncs.getLidState());
     }
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index a2425a3..b014372 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -702,16 +702,6 @@
     public int checkAddPermission(WindowManager.LayoutParams attrs, int[] outAppOp);
 
     /**
-     * Check permissions when adding a window.
-     *
-     * @param attrs The window's LayoutParams.
-     *
-     * @return True if the window may only be shown to the current user, false if the window can
-     * be shown on all users' windows.
-     */
-    public boolean checkShowToOwnerOnly(WindowManager.LayoutParams attrs);
-
-    /**
      * After the window manager has computed the current configuration based
      * on its knowledge of the display and input devices, it gives the policy
      * a chance to adjust the information contained in it.  If you want to
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index f0e4625..4142e6f 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -49,6 +49,7 @@
 import com.android.server.power.batterysaver.BatterySavingStats.InteractiveState;
 
 import java.util.ArrayList;
+import java.util.Objects;
 
 /**
  * Responsible for battery saver mode transition logic.
@@ -237,7 +238,7 @@
     private PowerManager getPowerManager() {
         if (mPowerManager == null) {
             mPowerManager =
-                    Preconditions.checkNotNull(mContext.getSystemService(PowerManager.class));
+                    Objects.requireNonNull(mContext.getSystemService(PowerManager.class));
         }
         return mPowerManager;
     }
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 9a65ae6..ae3f368 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -780,6 +780,33 @@
         return enableRollbackForPackageSession(newRollback.rollback, packageSession);
     }
 
+    private void removeRollbackForPackageSessionId(int sessionId) {
+        if (LOCAL_LOGV) {
+            Slog.v(TAG, "removeRollbackForPackageSessionId=" + sessionId);
+        }
+
+        synchronized (mLock) {
+            NewRollback newRollback = getNewRollbackForPackageSessionLocked(sessionId);
+            if (newRollback != null) {
+                Slog.w(TAG, "Delete new rollback id=" + newRollback.rollback.info.getRollbackId()
+                        + " for session id=" + sessionId);
+                mNewRollbacks.remove(newRollback);
+                newRollback.rollback.delete(mAppDataRollbackHelper);
+            }
+            Iterator<Rollback> iter = mRollbacks.iterator();
+            while (iter.hasNext()) {
+                Rollback rollback = iter.next();
+                if (rollback.getStagedSessionId() == sessionId) {
+                    Slog.w(TAG, "Delete rollback id=" + rollback.info.getRollbackId()
+                            + " for session id=" + sessionId);
+                    iter.remove();
+                    rollback.delete(mAppDataRollbackHelper);
+                    break;
+                }
+            }
+        }
+    }
+
     /**
      * Do code and userdata backups to enable rollback of the given session.
      * In case of multiPackage sessions, <code>session</code> should be one of
@@ -944,7 +971,7 @@
                 }
             }
 
-            Rollback rollback = completeEnableRollback(newRollback, true);
+            Rollback rollback = completeEnableRollback(newRollback);
             if (rollback == null) {
                 result.offer(-1);
             } else {
@@ -1089,23 +1116,29 @@
             if (LOCAL_LOGV) {
                 Slog.v(TAG, "SessionCallback.onFinished id=" + sessionId + " success=" + success);
             }
-            NewRollback newRollback;
-            synchronized (mLock) {
-                newRollback = getNewRollbackForPackageSessionLocked(sessionId);
+
+            if (success) {
+                NewRollback newRollback;
+                synchronized (mLock) {
+                    newRollback = getNewRollbackForPackageSessionLocked(sessionId);
+                    if (newRollback != null && newRollback.notifySessionWithSuccess()) {
+                        mNewRollbacks.remove(newRollback);
+                    } else {
+                        // Not all child sessions finished with success.
+                        // Don't enable the rollback yet.
+                        newRollback = null;
+                    }
+                }
+
                 if (newRollback != null) {
-                    mNewRollbacks.remove(newRollback);
+                    Rollback rollback = completeEnableRollback(newRollback);
+                    if (rollback != null && !rollback.isStaged()) {
+                        makeRollbackAvailable(rollback);
+                    }
                 }
+            } else {
+                removeRollbackForPackageSessionId(sessionId);
             }
-
-            if (newRollback != null) {
-                Rollback rollback = completeEnableRollback(newRollback, success);
-                if (rollback != null && !rollback.isStaged()) {
-                    makeRollbackAvailable(rollback);
-                }
-            }
-
-            // Clear the queue so it will never be leaked to next tests.
-            mSleepDuration.clear();
         }
     }
 
@@ -1116,16 +1149,10 @@
      * @return the Rollback instance for a successfully enable-completed rollback,
      * or null on error.
      */
-    private Rollback completeEnableRollback(NewRollback newRollback, boolean success) {
+    private Rollback completeEnableRollback(NewRollback newRollback) {
         Rollback rollback = newRollback.rollback;
         if (LOCAL_LOGV) {
-            Slog.v(TAG, "completeEnableRollback id="
-                    + rollback.info.getRollbackId() + " success=" + success);
-        }
-        if (!success) {
-            // The install session was aborted, clean up the pending install.
-            rollback.delete(mAppDataRollbackHelper);
-            return null;
+            Slog.v(TAG, "completeEnableRollback id=" + rollback.info.getRollbackId());
         }
 
         if (newRollback.isCancelled()) {
@@ -1251,6 +1278,14 @@
         @GuardedBy("mNewRollbackLock")
         private boolean mIsCancelled = false;
 
+        /**
+         * The number of sessions in the install which are notified with success by
+         * {@link PackageInstaller.SessionCallback#onFinished(int, boolean)}.
+         * This NewRollback will be enabled only after all child sessions finished with success.
+         */
+        @GuardedBy("mNewRollbackLock")
+        private int mNumPackageSessionsWithSuccess;
+
         private final Object mNewRollbackLock = new Object();
 
         NewRollback(Rollback rollback, int[] packageSessionIds) {
@@ -1322,6 +1357,17 @@
         int getPackageSessionIdCount() {
             return mPackageSessionIds.length;
         }
+
+        /**
+         * Called when a child session finished with success.
+         * Returns true when all child sessions are notified with success. This NewRollback will be
+         * enabled only after all child sessions finished with success.
+         */
+        boolean notifySessionWithSuccess() {
+            synchronized (mNewRollbackLock) {
+                return ++mNumPackageSessionsWithSuccess == mPackageSessionIds.length;
+            }
+        }
     }
 
     @GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 162a695..a0ef8cf 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -333,9 +333,24 @@
         return rollbackId;
     }
 
+    private static String rollbackTypeToString(int type) {
+        switch (type) {
+            case StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE:
+                return "ROLLBACK_INITIATE";
+            case StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS:
+                return "ROLLBACK_SUCCESS";
+            case StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE:
+                return "ROLLBACK_FAILURE";
+            case StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED:
+                return "ROLLBACK_BOOT_TRIGGERED";
+            default:
+                return "UNKNOWN";
+        }
+    }
+
     private static void logEvent(@Nullable VersionedPackage moduleMetadataPackage, int type,
             int rollbackReason, @NonNull String failingPackageName) {
-        Slog.i(TAG, "Watchdog event occurred of type: " + type);
+        Slog.i(TAG, "Watchdog event occurred of type: " + rollbackTypeToString(type));
         if (moduleMetadataPackage != null) {
             StatsLog.logWatchdogRollbackOccurred(type, moduleMetadataPackage.getPackageName(),
                     moduleMetadataPackage.getVersionCode(), rollbackReason, failingPackageName);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 76d18fa..8bedeae 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -521,7 +521,7 @@
     static final int STARTING_WINDOW_SHOWN = 1;
     static final int STARTING_WINDOW_REMOVED = 2;
     int mStartingWindowState = STARTING_WINDOW_NOT_SHOWN;
-    boolean mTaskOverlay = false; // Task is always on-top of other activities in the task.
+    private boolean mTaskOverlay = false; // Task is always on-top of other activities in the task.
 
     // Marking the reason why this activity is being relaunched. Mainly used to track that this
     // activity is being relaunched to fulfill a resize request due to compatibility issues, e.g. in
@@ -1222,7 +1222,7 @@
     }
 
     ActivityStack getStack() {
-        return task != null ? task.getTaskStack() : null;
+        return task != null ? task.getStack() : null;
     }
 
     @Override
@@ -1269,8 +1269,8 @@
             if (getDisplayContent() != null) {
                 getDisplayContent().mClosingApps.remove(this);
             }
-        } else if (mLastParent != null && mLastParent.getTaskStack() != null) {
-            task.getTaskStack().mExitingActivities.remove(this);
+        } else if (mLastParent != null && mLastParent.getStack() != null) {
+            task.getStack().mExitingActivities.remove(this);
         }
         final ActivityStack stack = getStack();
 
@@ -1974,15 +1974,6 @@
                     + " is already the parent of r=" + this);
         }
 
-        // TODO: Ensure that we do not directly reparent activities across stacks, as that may leave
-        //       the stacks in strange states. For now, we should use Task.reparent() to ensure that
-        //       the stack is left in an OK state.
-        if (prevTask != null && newTask != null && prevTask.getStack() != newTask.getStack()) {
-            throw new IllegalArgumentException(reason + ": task=" + newTask
-                    + " is in a different stack (" + newTask.getStackId() + ") than the parent of"
-                    + " r=" + this + " (" + prevTask.getStackId() + ")");
-        }
-
         ProtoLog.i(WM_DEBUG_ADD_REMOVE, "reparent: moving activity=%s"
                 + " to task=%d at %d", this, task.mTaskId, position);
         reparent(newTask, position);
@@ -2633,14 +2624,13 @@
         // TODO(b/137329632): find the next activity directly underneath this one, not just anywhere
         final ActivityRecord next = getDisplay().topRunningActivity(
                 true /* considerKeyguardState */);
-        final boolean isVisible = mVisibleRequested || nowVisible;
         // isNextNotYetVisible is to check if the next activity is invisible, or it has been
         // requested to be invisible but its windows haven't reported as invisible.  If so, it
         // implied that the current finishing activity should be added into stopping list rather
         // than destroy immediately.
         final boolean isNextNotYetVisible = next != null
                 && (!next.nowVisible || !next.mVisibleRequested);
-        if (isVisible && isNextNotYetVisible) {
+        if ((mVisibleRequested || isState(PAUSED)) && 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 */,
@@ -4772,7 +4762,7 @@
         }
 
         // Schedule an idle timeout in case the app doesn't do it for us.
-        mStackSupervisor.scheduleIdleTimeoutLocked(this);
+        mStackSupervisor.scheduleIdleTimeout(this);
 
         mStackSupervisor.reportResumedActivityLocked(this);
 
@@ -4993,9 +4983,9 @@
                         + "immediate=" + !idleDelayed);
             }
             if (!idleDelayed) {
-                mStackSupervisor.scheduleIdleLocked();
+                mStackSupervisor.scheduleIdle();
             } else {
-                mStackSupervisor.scheduleIdleTimeoutLocked(this);
+                mStackSupervisor.scheduleIdleTimeout(this);
             }
         } else {
             stack.checkReadyForSleep();
@@ -5523,7 +5513,7 @@
         if (stack == null) {
             return INVALID_DISPLAY;
         }
-        return stack.mDisplayId;
+        return stack.getDisplayId();
     }
 
     final boolean isDestroyable() {
@@ -6111,13 +6101,13 @@
             // the full stop of this activity. This is because we won't do that while they are still
             // waiting for the animation to finish.
             if (mAtmService.mStackSupervisor.mStoppingActivities.contains(this)) {
-                mAtmService.mStackSupervisor.scheduleIdleLocked();
+                mStackSupervisor.scheduleIdle();
             }
         } else {
             // Instead of doing the full stop routine here, let's just hide any activities
             // we now can, and let them stop when the normal idle happens.
-            mAtmService.mStackSupervisor.processStoppingActivitiesLocked(null /* idleActivity */,
-                    false /* remove */, true /* processPausingActivities */);
+            mStackSupervisor.processStoppingActivities(null /* launchedActivity */,
+                    true /* onlyUpdateVisibility */, true /* unused */, null /* unused */);
         }
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
@@ -7451,6 +7441,20 @@
         return this == rootActivity;
     }
 
+    void setTaskOverlay(boolean taskOverlay) {
+        mTaskOverlay = taskOverlay;
+        setAlwaysOnTop(mTaskOverlay);
+    }
+
+    boolean isTaskOverlay() {
+        return mTaskOverlay;
+    }
+
+    @Override
+    boolean showToCurrentUser() {
+        return mShowForAllUsers || mWmService.isCurrentProfile(mUserId);
+    }
+
     @Override
     public String toString() {
         if (stringName != null) {
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 16245f0..ef34327 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -70,6 +70,7 @@
 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.ActivityStackSupervisor.DEFER_RESUME;
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.ActivityStackSupervisor.dumpHistoryList;
 import static com.android.server.wm.ActivityStackSupervisor.printThisActivity;
@@ -310,7 +311,7 @@
     int mCurrentUser;
 
     /** The attached Display's unique identifier, or -1 if detached */
-    int mDisplayId;
+    private int mDisplayId;
     // Id of the previous display the stack was on.
     int mPrevDisplayId = INVALID_DISPLAY;
 
@@ -808,8 +809,8 @@
      * @return {@code true} if the windowing mode is transient, {@code false} otherwise.
      */
     private static boolean isTransientWindowingMode(int windowingMode) {
-        // TODO(b/114842032): add PIP if/when it uses mode transitions instead of task reparenting
-        return windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+        return windowingMode == WINDOWING_MODE_PINNED
+                || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
                 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
     }
 
@@ -1013,6 +1014,10 @@
         return getDisplayContent();
     }
 
+    int getDisplayId() {
+        return mDisplayId;
+    }
+
     /**
      * Defers updating the bounds of the stack. If the stack was resized/repositioned while
      * deferring, the bounds will update in {@link #continueUpdateBounds()}.
@@ -1082,7 +1087,7 @@
     }
 
     private ActivityRecord topRunningNonOverlayTaskActivity() {
-        return getActivity((r) -> (r.canBeTopRunning() && !r.mTaskOverlay));
+        return getActivity((r) -> (r.canBeTopRunning() && !r.isTaskOverlay()));
     }
 
     ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
@@ -1253,7 +1258,7 @@
 
         super.switchUser(userId);
         forAllTasks((t) -> {
-            if (t.mWmService.isCurrentProfileLocked(t.mUserId) || t.showForAllUsers()) {
+            if (t.mWmService.isCurrentProfile(t.mUserId) || t.showForAllUsers()) {
                 mChildren.remove(t);
                 mChildren.add(t);
             }
@@ -1271,7 +1276,7 @@
         // Make sure that there is no activity waiting for this to launch.
         if (!mStackSupervisor.mWaitingActivityLaunched.isEmpty()) {
             mStackSupervisor.removeIdleTimeoutForActivity(r);
-            mStackSupervisor.scheduleIdleTimeoutLocked(r);
+            mStackSupervisor.scheduleIdleTimeout(r);
         }
     }
 
@@ -1324,7 +1329,7 @@
                 if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to stop "
                         + mStackSupervisor.mStoppingActivities.size() + " activities");
 
-                mStackSupervisor.scheduleIdleLocked();
+                mStackSupervisor.scheduleIdle();
                 shouldSleep = false;
             }
 
@@ -1830,6 +1835,15 @@
                 && (topTask == null || topTask.supportsSplitScreenWindowingMode());
     }
 
+    /**
+     * Returns {@code true} if this is the top-most split-screen-primary or
+     * split-screen-secondary stack, {@code false} otherwise.
+     */
+    boolean isTopSplitScreenStack() {
+        return inSplitScreenWindowingMode()
+                && this == getDisplay().getTopStackInWindowingMode(getWindowingMode());
+    }
+
     /** @return True if the resizing of the primary-split-screen stack affects this stack size. */
     boolean affectedBySplitScreenResize() {
         if (!supportsSplitScreenWindowingMode()) {
@@ -2665,7 +2679,7 @@
         final Task task = taskTop.getTask();
 
         // If ActivityOptions are moved out and need to be aborted or moved to taskTop.
-        final ActivityOptions topOptions = sResetTargetTaskHelper.process(this, task, forceReset);
+        final ActivityOptions topOptions = sResetTargetTaskHelper.process(task, forceReset);
 
         if (mChildren.contains(task)) {
             final ActivityRecord newTop = task.getTopNonFinishingActivity();
@@ -2999,6 +3013,11 @@
 
     final void moveTaskToFrontLocked(Task tr, boolean noAnimation, ActivityOptions options,
             AppTimeTracker timeTracker, String reason) {
+        moveTaskToFrontLocked(tr, noAnimation, options, timeTracker, !DEFER_RESUME, reason);
+    }
+
+    final void moveTaskToFrontLocked(Task tr, boolean noAnimation, ActivityOptions options,
+            AppTimeTracker timeTracker, boolean deferResume, String reason) {
         if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
 
         final ActivityStack topStack = getDisplay().getTopStack();
@@ -3070,7 +3089,9 @@
                 topActivity.supportsEnterPipOnTaskSwitch = true;
             }
 
-            mRootWindowContainer.resumeFocusedStacksTopActivities();
+            if (!deferResume) {
+                mRootWindowContainer.resumeFocusedStacksTopActivities();
+            }
             EventLogTags.writeWmTaskToFront(tr.mUserId, tr.mTaskId);
             mAtmService.getTaskChangeNotificationController().notifyTaskMovedToFront(tr.getTaskInfo());
         } finally {
@@ -3965,11 +3986,19 @@
      * @param showForAllUsers Whether to show the task regardless of the current user.
      */
     private void addChild(Task task, int position, boolean showForAllUsers, boolean moveParents) {
-        // Add child task.
-        addChild(task, null);
+        try {
+            // Force show for all user so task can be position correctly based on which user is
+            // active. We clear the force show below.
+            task.setForceShowForAllUsers(showForAllUsers);
+            // Add child task.
+            addChild(task, null);
 
-        // Move child to a proper position, as some restriction for position might apply.
-        positionChildAt(position, task, moveParents /* includingParents */, showForAllUsers);
+            // Move child to a proper position, as some restriction for position might apply.
+            positionChildAt(position, task, moveParents /* includingParents */);
+
+        } finally {
+            task.setForceShowForAllUsers(false);
+        }
     }
 
     @Override
@@ -4015,18 +4044,7 @@
     @Override
     void positionChildAt(int position, WindowContainer child, boolean includingParents) {
         final Task task = (Task) child;
-        positionChildAt(position, task, includingParents, task.showForAllUsers());
-    }
-
-    /**
-     * Overridden version of {@link ActivityStack#positionChildAt(int, WindowContainer, boolean)}.
-     * Used in {@link ActivityStack#addChild(Task, int, boolean showForAllUsers, boolean)}, as it
-     * can receive showForAllUsers param from {@link ActivityRecord} instead of
-     * {@link Task#showForAllUsers()}.
-     */
-    private int positionChildAt(int position, Task child, boolean includingParents,
-            boolean showForAllUsers) {
-        final int targetPosition = findPositionForTask(child, position, showForAllUsers);
+        final int targetPosition = findPositionForTask(task, position);
         super.positionChildAt(targetPosition, child, includingParents);
 
         // Log positioning.
@@ -4035,8 +4053,7 @@
         }
 
         final int toTop = targetPosition == mChildren.size() - 1 ? 1 : 0;
-        EventLogTags.writeWmTaskMoved(child.mTaskId, toTop, targetPosition);
-        return targetPosition;
+        EventLogTags.writeWmTaskMoved(task.mTaskId, toTop, targetPosition);
     }
 
     @Override
@@ -4106,9 +4123,8 @@
 
     // TODO: We should really have users as a window container in the hierarchy so that we don't
     // have to do complicated things like we are doing in this method.
-    int findPositionForTask(Task task, int targetPosition, boolean showForAllUsers) {
-        final boolean canShowTask =
-                showForAllUsers || mWmService.isCurrentProfileLocked(task.mUserId);
+    int findPositionForTask(Task task, int targetPosition) {
+        final boolean canShowTask = task.showToCurrentUser();
 
         final int stackSize = mChildren.size();
         int minPosition = 0;
@@ -4140,9 +4156,7 @@
     private int computeMinPosition(int minPosition, int size) {
         while (minPosition < size) {
             final Task tmpTask = (Task) mChildren.get(minPosition);
-            final boolean canShowTmpTask =
-                    tmpTask.showForAllUsers()
-                            || mWmService.isCurrentProfileLocked(tmpTask.mUserId);
+            final boolean canShowTmpTask = tmpTask.showToCurrentUser();
             if (canShowTmpTask) {
                 break;
             }
@@ -4160,9 +4174,7 @@
     private int computeMaxPosition(int maxPosition) {
         while (maxPosition > 0) {
             final Task tmpTask = (Task) mChildren.get(maxPosition);
-            final boolean canShowTmpTask =
-                    tmpTask.showForAllUsers()
-                            || mWmService.isCurrentProfileLocked(tmpTask.mUserId);
+            final boolean canShowTmpTask = tmpTask.showToCurrentUser();
             if (!canShowTmpTask) {
                 break;
             }
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index a380efc4..ed73943 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -571,14 +571,14 @@
         }
     }
 
-    void setNextTaskIdForUserLocked(int taskId, int userId) {
+    void setNextTaskIdForUser(int taskId, int userId) {
         final int currentTaskId = mCurTaskIdForUser.get(userId, -1);
         if (taskId > currentTaskId) {
             mCurTaskIdForUser.put(userId, taskId);
         }
     }
 
-    static int nextTaskIdForUser(int taskId, int userId) {
+    private static int nextTaskIdForUser(int taskId, int userId) {
         int nextTaskId = taskId + 1;
         if (nextTaskId == (userId + 1) * MAX_TASK_IDS_PER_USER) {
             // Wrap around as there will be smaller task ids that are available now.
@@ -587,7 +587,11 @@
         return nextTaskId;
     }
 
-    int getNextTaskIdForUserLocked(int userId) {
+    int getNextTaskIdForUser() {
+        return getNextTaskIdForUser(mRootWindowContainer.mCurrentUser);
+    }
+
+    int getNextTaskIdForUser(int userId) {
         final int currentTaskId = mCurTaskIdForUser.get(userId, userId * MAX_TASK_IDS_PER_USER);
         // for a userId u, a taskId can only be in the range
         // [u*MAX_TASK_IDS_PER_USER, (u+1)*MAX_TASK_IDS_PER_USER-1], so if MAX_TASK_IDS_PER_USER
@@ -1211,8 +1215,8 @@
         }
 
         // TODO moltmann b/136595429: Set featureId from caller
-        if (mService.getAppOpsService().noteOperation(opCode, callingUid, callingPackage, /* featureId */ null)
-                != AppOpsManager.MODE_ALLOWED) {
+        if (mService.getAppOpsService().noteOperation(opCode, callingUid,
+                callingPackage, /* featureId */ null, false, "") != AppOpsManager.MODE_ALLOWED) {
             if (!ignoreTargetSecurity) {
                 return ACTIVITY_RESTRICTION_APPOP;
             }
@@ -1254,9 +1258,9 @@
             return ACTIVITY_RESTRICTION_NONE;
         }
 
-        // TODO moltmann b/136595429: Set componentId from caller
-        if (mService.getAppOpsService().noteOperation(opCode, callingUid, callingPackage, /* featureId */ null)
-                != AppOpsManager.MODE_ALLOWED) {
+        // TODO moltmann b/136595429: Set featureId from caller
+        if (mService.getAppOpsService().noteOperation(opCode, callingUid,
+                callingPackage, /* featureId */ null, false, "") != AppOpsManager.MODE_ALLOWED) {
             return ACTIVITY_RESTRICTION_APPOP;
         }
 
@@ -1297,22 +1301,14 @@
         return booting;
     }
 
-    // Checked.
-    @GuardedBy("mService")
-    final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
+    void activityIdleInternal(ActivityRecord r, boolean fromTimeout,
             boolean processPausingActivities, Configuration config) {
-        if (DEBUG_ALL) Slog.v(TAG, "Activity idle: " + token);
+        if (DEBUG_ALL) Slog.v(TAG, "Activity idle: " + r);
 
-        ArrayList<ActivityRecord> finishes = null;
-        ArrayList<UserState> startingUsers = null;
-        int NS = 0;
-        int NF = 0;
         boolean booting = false;
-        boolean activityRemoved = false;
 
-        ActivityRecord r = ActivityRecord.forTokenLocked(token);
         if (r != null) {
-            if (DEBUG_IDLE) Slog.d(TAG_IDLE, "activityIdleInternalLocked: Callers="
+            if (DEBUG_IDLE) Slog.d(TAG_IDLE, "activityIdleInternal: Callers="
                     + Debug.getCallers(4));
             mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
             r.finishLaunchTickingLocked();
@@ -1365,47 +1361,14 @@
         }
 
         // Atomically retrieve all of the other things to do.
-        final ArrayList<ActivityRecord> stops = processStoppingActivitiesLocked(r,
-                true /* remove */, processPausingActivities);
-        NS = stops != null ? stops.size() : 0;
-        if ((NF = mFinishingActivities.size()) > 0) {
-            finishes = new ArrayList<>(mFinishingActivities);
-            mFinishingActivities.clear();
-        }
+        processStoppingAndFinishingActivities(r, processPausingActivities, "idle");
 
-        if (mStartingUsers.size() > 0) {
-            startingUsers = new ArrayList<>(mStartingUsers);
+        if (!mStartingUsers.isEmpty()) {
+            final ArrayList<UserState> startingUsers = new ArrayList<>(mStartingUsers);
             mStartingUsers.clear();
-        }
 
-        // Stop any activities that are scheduled to do so but have been
-        // waiting for the next one to start.
-        for (int i = 0; i < NS; i++) {
-            r = stops.get(i);
-            final ActivityStack stack = r.getActivityStack();
-            if (stack != null) {
-                if (r.finishing) {
-                    // TODO(b/137329632): Wait for idle of the right activity, not just any.
-                    r.destroyIfPossible("activityIdleInternalLocked");
-                } else {
-                    r.stopIfPossible();
-                }
-            }
-        }
-
-        // Finish any activities that are scheduled to do so but have been
-        // waiting for the next one to start.
-        for (int i = 0; i < NF; i++) {
-            r = finishes.get(i);
-            final ActivityStack stack = r.getActivityStack();
-            if (stack != null) {
-                activityRemoved |= r.destroyImmediately(true /* removeFromApp */, "finish-idle");
-            }
-        }
-
-        if (!booting) {
-            // Complete user switch
-            if (startingUsers != null) {
+            if (!booting) {
+                // Complete user switch.
                 for (int i = 0; i < startingUsers.size(); i++) {
                     mService.mAmInternal.finishUserSwitch(startingUsers.get(i));
                 }
@@ -1413,14 +1376,6 @@
         }
 
         mService.mH.post(() -> mService.mAmInternal.trimApplications());
-        //dump();
-        //mWindowManager.dump();
-
-        if (activityRemoved) {
-            mRootWindowContainer.resumeFocusedStacksTopActivities();
-        }
-
-        return r;
     }
 
     /** This doesn't just find a task, it also moves the task to front. */
@@ -1761,7 +1716,7 @@
             stack.mForceHidden = true;
             stack.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
             stack.mForceHidden = false;
-            activityIdleInternalLocked(null, false /* fromTimeout */,
+            activityIdleInternal(null /* idleActivity */, false /* fromTimeout */,
                     true /* processPausingActivities */, null /* configuration */);
 
             // Move all the tasks to the bottom of the fullscreen stack
@@ -1955,7 +1910,7 @@
 
         // Ensure that we're not moving a task to a dynamic stack if device doesn't support
         // multi-display.
-        if (stack.mDisplayId != DEFAULT_DISPLAY && !mService.mSupportsMultiDisplay) {
+        if (stack.getDisplayId() != DEFAULT_DISPLAY && !mService.mSupportsMultiDisplay) {
             throw new IllegalArgumentException("Device doesn't support multi-display, can not"
                     + " reparent task=" + task + " to stackId=" + stackId);
         }
@@ -2129,19 +2084,46 @@
         return false;
     }
 
-    // TODO: Change method name to reflect what it actually does.
-    final ArrayList<ActivityRecord> processStoppingActivitiesLocked(ActivityRecord idleActivity,
-            boolean remove, boolean processPausingActivities) {
-        ArrayList<ActivityRecord> stops = null;
+    /**
+     * Processes the activities to be stopped or destroyed. This should be called when the resumed
+     * activities are idle or drawn.
+     */
+    private void processStoppingAndFinishingActivities(ActivityRecord launchedActivity,
+            boolean processPausingActivities, String reason) {
+        // Stop any activities that are scheduled to do so but have been waiting for the transition
+        // animation to finish.
+        processStoppingActivities(launchedActivity, false /* onlyUpdateVisibility */,
+                processPausingActivities, reason);
+
+        final int numFinishingActivities = mFinishingActivities.size();
+        if (numFinishingActivities == 0) {
+            return;
+        }
+
+        // Finish any activities that are scheduled to do so but have been waiting for the next one
+        // to start.
+        final ArrayList<ActivityRecord> finishingActivities = new ArrayList<>(mFinishingActivities);
+        mFinishingActivities.clear();
+        for (int i = 0; i < numFinishingActivities; i++) {
+            final ActivityRecord r = finishingActivities.get(i);
+            if (r.isInHistory()) {
+                r.destroyImmediately(true /* removeFromApp */, "finish-" + reason);
+            }
+        }
+    }
+
+    /** Stop or destroy the stopping activities if they are not interactive. */
+    void processStoppingActivities(ActivityRecord launchedActivity, boolean onlyUpdateVisibility,
+            boolean processPausingActivities, String reason) {
+        final int numStoppingActivities = mStoppingActivities.size();
+        if (numStoppingActivities == 0) {
+            return;
+        }
+        ArrayList<ActivityRecord> readyToStopActivities = null;
 
         final boolean nowVisible = mRootWindowContainer.allResumedActivitiesVisible();
-        for (int activityNdx = mStoppingActivities.size() - 1; activityNdx >= 0; --activityNdx) {
-            ActivityRecord s = mStoppingActivities.get(activityNdx);
-
-            final boolean animating = s.isAnimating(TRANSITION);
-
-            if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + nowVisible
-                    + " animating=" + animating + " finishing=" + s.finishing);
+        for (int activityNdx = numStoppingActivities - 1; activityNdx >= 0; --activityNdx) {
+            final ActivityRecord s = mStoppingActivities.get(activityNdx);
             if (nowVisible && s.finishing) {
 
                 // If this activity is finishing, it is sitting on top of
@@ -2152,32 +2134,49 @@
                 if (DEBUG_STATES) Slog.v(TAG, "Before stopping, can hide: " + s);
                 s.setVisibility(false);
             }
-            if (remove) {
-                final ActivityStack stack = s.getActivityStack();
-                final boolean shouldSleepOrShutDown = stack != null
-                        ? stack.shouldSleepOrShutDownActivities()
-                        : mService.isSleepingOrShuttingDownLocked();
-                if (!animating || shouldSleepOrShutDown) {
-                    if (!processPausingActivities && s.isState(PAUSING)) {
-                        // Defer processing pausing activities in this iteration and reschedule
-                        // a delayed idle to reprocess it again
-                        removeIdleTimeoutForActivity(idleActivity);
-                        scheduleIdleTimeoutLocked(idleActivity);
-                        continue;
-                    }
+            if (onlyUpdateVisibility) {
+                continue;
+            }
 
-                    if (DEBUG_STATES) Slog.v(TAG, "Ready to stop: " + s);
-                    if (stops == null) {
-                        stops = new ArrayList<>();
-                    }
-                    stops.add(s);
+            final boolean animating = s.isAnimating(TRANSITION);
+            if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + nowVisible
+                    + " animating=" + animating + " finishing=" + s.finishing);
 
-                    mStoppingActivities.remove(activityNdx);
+            final ActivityStack stack = s.getActivityStack();
+            final boolean shouldSleepOrShutDown = stack != null
+                    ? stack.shouldSleepOrShutDownActivities()
+                    : mService.isSleepingOrShuttingDownLocked();
+            if (!animating || shouldSleepOrShutDown) {
+                if (!processPausingActivities && s.isState(PAUSING)) {
+                    // Defer processing pausing activities in this iteration and reschedule
+                    // a delayed idle to reprocess it again
+                    removeIdleTimeoutForActivity(launchedActivity);
+                    scheduleIdleTimeout(launchedActivity);
+                    continue;
                 }
+
+                if (DEBUG_STATES) Slog.v(TAG, "Ready to stop: " + s);
+                if (readyToStopActivities == null) {
+                    readyToStopActivities = new ArrayList<>();
+                }
+                readyToStopActivities.add(s);
+
+                mStoppingActivities.remove(activityNdx);
             }
         }
 
-        return stops;
+        final int numReadyStops = readyToStopActivities == null ? 0 : readyToStopActivities.size();
+        for (int i = 0; i < numReadyStops; i++) {
+            final ActivityRecord r = readyToStopActivities.get(i);
+            if (r.isInHistory()) {
+                if (r.finishing) {
+                    // TODO(b/137329632): Wait for idle of the right activity, not just any.
+                    r.destroyIfPossible(reason);
+                } else {
+                    r.stopIfPossible();
+                }
+            }
+        }
     }
 
     void removeHistoryRecords(WindowProcessController app) {
@@ -2315,14 +2314,13 @@
         return printed;
     }
 
-    void scheduleIdleTimeoutLocked(ActivityRecord next) {
-        if (DEBUG_IDLE) Slog.d(TAG_IDLE,
-                "scheduleIdleTimeoutLocked: Callers=" + Debug.getCallers(4));
+    void scheduleIdleTimeout(ActivityRecord next) {
+        if (DEBUG_IDLE) Slog.d(TAG_IDLE, "scheduleIdleTimeout: Callers=" + Debug.getCallers(4));
         Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG, next);
         mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
     }
 
-    final void scheduleIdleLocked() {
+    final void scheduleIdle() {
         mHandler.sendEmptyMessage(IDLE_NOW_MSG);
     }
 
@@ -2443,7 +2441,7 @@
 
         // Handle incorrect launch/move to secondary display if needed.
         if (isSecondaryDisplayPreferred) {
-            final int actualDisplayId = task.getStack().mDisplayId;
+            final int actualDisplayId = task.getDisplayId();
             if (!task.canBeLaunchedOnDisplay(actualDisplayId)) {
                 throw new IllegalStateException("Task resolved to incompatible display");
             }
@@ -2616,83 +2614,19 @@
 
     private final class ActivityStackSupervisorHandler extends Handler {
 
-        public ActivityStackSupervisorHandler(Looper looper) {
+        ActivityStackSupervisorHandler(Looper looper) {
             super(looper);
         }
 
-        void activityIdleInternal(ActivityRecord r, boolean processPausingActivities) {
-            synchronized (mService.mGlobalLock) {
-                activityIdleInternalLocked(r != null ? r.appToken : null, true /* fromTimeout */,
-                        processPausingActivities, null);
-            }
-        }
-
         @Override
         public void handleMessage(Message msg) {
+            synchronized (mService.mGlobalLock) {
+                if (handleMessageInner(msg)) {
+                    return;
+                }
+            }
+            // The cases that some invocations cannot be locked by WM.
             switch (msg.what) {
-                case REPORT_MULTI_WINDOW_MODE_CHANGED_MSG: {
-                    synchronized (mService.mGlobalLock) {
-                        for (int i = mMultiWindowModeChangedActivities.size() - 1; i >= 0; i--) {
-                            final ActivityRecord r = mMultiWindowModeChangedActivities.remove(i);
-                            r.updateMultiWindowMode();
-                        }
-                    }
-                } break;
-                case REPORT_PIP_MODE_CHANGED_MSG: {
-                    synchronized (mService.mGlobalLock) {
-                        for (int i = mPipModeChangedActivities.size() - 1; i >= 0; i--) {
-                            final ActivityRecord r = mPipModeChangedActivities.remove(i);
-                            r.updatePictureInPictureMode(mPipModeChangedTargetStackBounds,
-                                    false /* forceUpdate */);
-                        }
-                    }
-                } break;
-                case IDLE_TIMEOUT_MSG: {
-                    if (DEBUG_IDLE) Slog.d(TAG_IDLE,
-                            "handleMessage: IDLE_TIMEOUT_MSG: r=" + msg.obj);
-                    // We don't at this point know if the activity is fullscreen,
-                    // so we need to be conservative and assume it isn't.
-                    activityIdleInternal((ActivityRecord) msg.obj,
-                            true /* processPausingActivities */);
-                } break;
-                case IDLE_NOW_MSG: {
-                    if (DEBUG_IDLE) Slog.d(TAG_IDLE, "handleMessage: IDLE_NOW_MSG: r=" + msg.obj);
-                    activityIdleInternal((ActivityRecord) msg.obj,
-                            false /* processPausingActivities */);
-                } break;
-                case RESUME_TOP_ACTIVITY_MSG: {
-                    synchronized (mService.mGlobalLock) {
-                        mRootWindowContainer.resumeFocusedStacksTopActivities();
-                    }
-                } break;
-                case SLEEP_TIMEOUT_MSG: {
-                    synchronized (mService.mGlobalLock) {
-                        if (mService.isSleepingOrShuttingDownLocked()) {
-                            Slog.w(TAG, "Sleep timeout!  Sleeping now.");
-                            checkReadyForSleepLocked(false /* allowDelay */);
-                        }
-                    }
-                } break;
-                case LAUNCH_TIMEOUT_MSG: {
-                    synchronized (mService.mGlobalLock) {
-                        if (mLaunchingActivityWakeLock.isHeld()) {
-                            Slog.w(TAG, "Launch timeout has expired, giving up wake lock!");
-                            if (VALIDATE_WAKE_LOCK_CALLER
-                                    && Binder.getCallingUid() != Process.myUid()) {
-                                throw new IllegalStateException("Calling must be system uid");
-                            }
-                            mLaunchingActivityWakeLock.release();
-                        }
-                    }
-                } break;
-                case LAUNCH_TASK_BEHIND_COMPLETE: {
-                    synchronized (mService.mGlobalLock) {
-                        ActivityRecord r = ActivityRecord.forTokenLocked((IBinder) msg.obj);
-                        if (r != null) {
-                            handleLaunchTaskBehindCompleteLocked(r);
-                        }
-                    }
-                } break;
                 case RESTART_ACTIVITY_PROCESS_TIMEOUT_MSG: {
                     final ActivityRecord r = (ActivityRecord) msg.obj;
                     String processName = null;
@@ -2709,26 +2643,89 @@
                                 "restartActivityProcessTimeout");
                     }
                 } break;
-                case REPORT_HOME_CHANGED_MSG: {
-                    synchronized (mService.mGlobalLock) {
-                        mHandler.removeMessages(REPORT_HOME_CHANGED_MSG);
+            }
+        }
 
-                        // Start home activities on displays with no activities.
-                        mRootWindowContainer.startHomeOnEmptyDisplays("homeChanged");
+        private void activityIdleFromMessage(ActivityRecord idleActivity, boolean fromTimeout) {
+            activityIdleInternal(idleActivity, fromTimeout,
+                    fromTimeout /* processPausingActivities */, null /* config */);
+        }
+
+        /**
+         * Handles the message with lock held.
+         *
+         * @return {@code true} if the message is handled.
+         */
+        private boolean handleMessageInner(Message msg) {
+            switch (msg.what) {
+                case REPORT_MULTI_WINDOW_MODE_CHANGED_MSG: {
+                    for (int i = mMultiWindowModeChangedActivities.size() - 1; i >= 0; i--) {
+                        final ActivityRecord r = mMultiWindowModeChangedActivities.remove(i);
+                        r.updateMultiWindowMode();
                     }
                 } break;
-                case TOP_RESUMED_STATE_LOSS_TIMEOUT_MSG: {
-                    ActivityRecord r = (ActivityRecord) msg.obj;
-                    Slog.w(TAG, "Activity top resumed state loss timeout for " + r);
-                    synchronized (mService.mGlobalLock) {
-                        if (r.hasProcess()) {
-                            mService.logAppTooSlow(r.app, r.topResumedStateLossTime,
-                                    "top state loss for " + r);
+                case REPORT_PIP_MODE_CHANGED_MSG: {
+                    for (int i = mPipModeChangedActivities.size() - 1; i >= 0; i--) {
+                        final ActivityRecord r = mPipModeChangedActivities.remove(i);
+                        r.updatePictureInPictureMode(mPipModeChangedTargetStackBounds,
+                                false /* forceUpdate */);
+                    }
+                } break;
+                case IDLE_TIMEOUT_MSG: {
+                    if (DEBUG_IDLE) Slog.d(TAG_IDLE,
+                            "handleMessage: IDLE_TIMEOUT_MSG: r=" + msg.obj);
+                    // We don't at this point know if the activity is fullscreen, so we need to be
+                    // conservative and assume it isn't.
+                    activityIdleFromMessage((ActivityRecord) msg.obj, true /* fromTimeout */);
+                } break;
+                case IDLE_NOW_MSG: {
+                    if (DEBUG_IDLE) Slog.d(TAG_IDLE, "handleMessage: IDLE_NOW_MSG: r=" + msg.obj);
+                    activityIdleFromMessage((ActivityRecord) msg.obj, false /* fromTimeout */);
+                } break;
+                case RESUME_TOP_ACTIVITY_MSG: {
+                    mRootWindowContainer.resumeFocusedStacksTopActivities();
+                } break;
+                case SLEEP_TIMEOUT_MSG: {
+                    if (mService.isSleepingOrShuttingDownLocked()) {
+                        Slog.w(TAG, "Sleep timeout!  Sleeping now.");
+                        checkReadyForSleepLocked(false /* allowDelay */);
+                    }
+                } break;
+                case LAUNCH_TIMEOUT_MSG: {
+                    if (mLaunchingActivityWakeLock.isHeld()) {
+                        Slog.w(TAG, "Launch timeout has expired, giving up wake lock!");
+                        if (VALIDATE_WAKE_LOCK_CALLER
+                                && Binder.getCallingUid() != Process.myUid()) {
+                            throw new IllegalStateException("Calling must be system uid");
                         }
+                        mLaunchingActivityWakeLock.release();
+                    }
+                } break;
+                case LAUNCH_TASK_BEHIND_COMPLETE: {
+                    final ActivityRecord r = ActivityRecord.forTokenLocked((IBinder) msg.obj);
+                    if (r != null) {
+                        handleLaunchTaskBehindCompleteLocked(r);
+                    }
+                } break;
+                case REPORT_HOME_CHANGED_MSG: {
+                    mHandler.removeMessages(REPORT_HOME_CHANGED_MSG);
+
+                    // Start home activities on displays with no activities.
+                    mRootWindowContainer.startHomeOnEmptyDisplays("homeChanged");
+                } break;
+                case TOP_RESUMED_STATE_LOSS_TIMEOUT_MSG: {
+                    final ActivityRecord r = (ActivityRecord) msg.obj;
+                    Slog.w(TAG, "Activity top resumed state loss timeout for " + r);
+                    if (r.hasProcess()) {
+                        mService.logAppTooSlow(r.app, r.topResumedStateLossTime,
+                                "top state loss for " + r);
                     }
                     handleTopResumedStateReleased(true /* timeout */);
                 } break;
+                default:
+                    return false;
             }
+            return true;
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 955e581..75d87ed 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -135,7 +135,7 @@
         mHandler = new StartHandler(mService.mH.getLooper());
         mFactory = factory;
         mFactory.setController(this);
-        mPendingRemoteAnimationRegistry = new PendingRemoteAnimationRegistry(service,
+        mPendingRemoteAnimationRegistry = new PendingRemoteAnimationRegistry(service.mGlobalLock,
                 service.mH);
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index a2b9d95..61ba15c 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -29,8 +29,6 @@
 import static android.app.ActivityManager.START_TASK_TO_FRONT;
 import static android.app.WaitResult.LAUNCH_STATE_COLD;
 import static android.app.WaitResult.LAUNCH_STATE_HOT;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
@@ -65,10 +63,8 @@
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_FOCUS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
@@ -1073,7 +1069,8 @@
                             mRootWindowContainer.getTopDisplayFocusedStack();
                     Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,
                             true, false) + "} from uid " + callingUid + " on display "
-                            + (focusedStack == null ? DEFAULT_DISPLAY : focusedStack.mDisplayId));
+                            + (focusedStack == null ? DEFAULT_DISPLAY
+                                    : focusedStack.getDisplayId()));
                 }
             }
         }
@@ -1487,11 +1484,6 @@
         mIntent.setFlags(mLaunchFlags);
 
         final Task reusedTask = getReusableTask();
-        mSupervisor.getLaunchParamsController().calculate(reusedTask != null ? reusedTask : mInTask,
-                r.info.windowLayout, r, sourceRecord, options, PHASE_BOUNDS, mLaunchParams);
-        mPreferredDisplayId =
-                mLaunchParams.hasPreferredDisplay() ? mLaunchParams.mPreferredDisplayId
-                        : DEFAULT_DISPLAY;
 
         // If requested, freeze the task list
         if (mOptions != null && mOptions.freezeRecentTasksReordering()
@@ -1505,6 +1497,8 @@
         final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
         final boolean newTask = targetTask == null;
 
+        computeLaunchParams(r, sourceRecord, targetTask);
+
         // Check if starting activity on given task or on a new task is allowed.
         int startResult = isAllowedToStart(r, newTask, targetTask);
         if (startResult != START_SUCCESS) {
@@ -1532,7 +1526,7 @@
         }
 
         if (mTargetStack == null) {
-            mTargetStack = computeStackFocus(mStartActivity, true, mLaunchFlags, mOptions);
+            mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, targetTask, mOptions);
         }
         if (newTask) {
             final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
@@ -1576,7 +1570,7 @@
             final ActivityRecord topTaskActivity =
                     mStartActivity.getTask().topRunningActivityLocked();
             if (!mTargetStack.isFocusable()
-                    || (topTaskActivity != null && topTaskActivity.mTaskOverlay
+                    || (topTaskActivity != null && topTaskActivity.isTaskOverlay()
                     && mStartActivity != topTaskActivity)) {
                 // If the activity is not focusable, we can't resume it, but still would like to
                 // make sure it becomes visible as it starts (this will also trigger entry
@@ -1622,15 +1616,49 @@
         } else if (mInTask != null) {
             return mInTask;
         } else {
-            final ActivityRecord top = computeStackFocus(mStartActivity, false /* newTask */,
-                    mLaunchFlags, mOptions).getTopNonFinishingActivity();
+            final ActivityStack stack = getLaunchStack(mStartActivity, mLaunchFlags,
+                    null /* task */, mOptions);
+            final ActivityRecord top = stack.getTopNonFinishingActivity();
             if (top != null) {
                 return top.getTask();
+            } else {
+                // Remove the stack if no activity in the stack.
+                stack.removeIfPossible();
             }
         }
         return null;
     }
 
+    private void computeLaunchParams(ActivityRecord r, ActivityRecord sourceRecord,
+            Task targetTask) {
+        final ActivityStack sourceStack = mSourceStack != null ? mSourceStack
+                : mRootWindowContainer.getTopDisplayFocusedStack();
+        if (sourceStack != null && sourceStack.inSplitScreenWindowingMode()
+                && (mOptions == null
+                        || mOptions.getLaunchWindowingMode() == WINDOWING_MODE_UNDEFINED)) {
+            int windowingMode =
+                    targetTask != null ? targetTask.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
+            if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
+                if (sourceStack.inSplitScreenPrimaryWindowingMode()) {
+                    windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+                } else if (sourceStack.inSplitScreenSecondaryWindowingMode()) {
+                    windowingMode = WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+                }
+            }
+
+            if (mOptions == null) {
+                mOptions = ActivityOptions.makeBasic();
+            }
+            mOptions.setLaunchWindowingMode(windowingMode);
+        }
+
+        mSupervisor.getLaunchParamsController().calculate(targetTask, r.info.windowLayout, r,
+                sourceRecord, mOptions, PHASE_BOUNDS, mLaunchParams);
+        mPreferredDisplayId =
+                mLaunchParams.hasPreferredDisplay() ? mLaunchParams.mPreferredDisplayId
+                        : DEFAULT_DISPLAY;
+    }
+
     private int isAllowedToStart(ActivityRecord r, boolean newTask, Task targetTask) {
         if (mStartActivity.packageName == null) {
             if (mStartActivity.resultTo != null) {
@@ -1869,8 +1897,8 @@
                 if (targetTask.getStack() == null) {
                     // Target stack got cleared when we all activities were removed above.
                     // Go ahead and reset it.
-                    mTargetStack = computeStackFocus(mSourceRecord, false /* newTask */,
-                            mLaunchFlags, mOptions);
+                    mTargetStack =
+                            getLaunchStack(mStartActivity, mLaunchFlags, null /* task */, mOptions);
                     mTargetStack.addChild(targetTask, !mLaunchTaskBehind /* toTop */,
                             (mStartActivity.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
                 }
@@ -2044,7 +2072,7 @@
 
         if (mOptions != null) {
             if (mOptions.getLaunchTaskId() != -1 && mOptions.getTaskOverlay()) {
-                r.mTaskOverlay = true;
+                r.setTaskOverlay(true);
                 if (!mOptions.canTaskOverlayResume()) {
                     final Task task = mRootWindowContainer.anyTaskForId(
                             mOptions.getLaunchTaskId());
@@ -2293,7 +2321,7 @@
         // the same behavior as if a new instance was being started, which means not bringing it
         // to the front if the caller is not itself in the front.
         final boolean differentTopTask;
-        if (mPreferredDisplayId == mTargetStack.mDisplayId) {
+        if (mPreferredDisplayId == mTargetStack.getDisplayId()) {
             final ActivityStack focusStack = mTargetStack.getDisplay().getFocusedStack();
             final ActivityRecord curTop = (focusStack == null)
                     ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
@@ -2319,57 +2347,25 @@
                 final ActivityStack launchStack =
                         getLaunchStack(mStartActivity, mLaunchFlags, intentTask, mOptions);
                 if (launchStack == null || launchStack == mTargetStack) {
+                    // Do not set mMovedToFront to true below for split-screen-top stack, or
+                    // START_TASK_TO_FRONT will be returned and trigger unexpected animations when a
+                    // new intent has delivered.
+                    final boolean isSplitScreenTopStack = mTargetStack.isTopSplitScreenStack();
+
                     // We only want to move to the front, if we aren't going to launch on a
                     // different stack. If we launch on a different stack, we will put the
                     // task on top there.
+                    // Defer resuming the top activity while moving task to top, since the
+                    // current task-top activity may not be the activity that should be resumed.
                     mTargetStack.moveTaskToFrontLocked(intentTask, mNoAnimation, mOptions,
-                            mStartActivity.appTimeTracker, "bringingFoundTaskToFront");
-                    mMovedToFront = true;
-                } else if (launchStack.inSplitScreenWindowingMode()) {
-                    if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
-                        // If we want to launch adjacent and mTargetStack is not the computed
-                        // launch stack - move task to top of computed stack.
-                        intentTask.reparent(launchStack, ON_TOP,
-                                REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
-                                "launchToSide");
-                    } else {
-                        // TODO: This should be reevaluated in MW v2.
-                        // We choose to move task to front instead of launching it adjacent
-                        // when specific stack was requested explicitly and it appeared to be
-                        // adjacent stack, but FLAG_ACTIVITY_LAUNCH_ADJACENT was not set.
-                        mTargetStack.moveTaskToFrontLocked(intentTask,
-                                mNoAnimation, mOptions, mStartActivity.appTimeTracker,
-                                "bringToFrontInsteadOfAdjacentLaunch");
-                    }
-                    mMovedToFront = launchStack != launchStack.getDisplay()
-                            .getTopStackInWindowingMode(launchStack.getWindowingMode());
-                } else if (launchStack.mDisplayId != mTargetStack.mDisplayId) {
-                    // Target and computed stacks are on different displays and we've
-                    // found a matching task - move the existing instance to that display and
-                    // move it to front.
-                    intentActivity.getTask().reparent(launchStack, ON_TOP,
-                            REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
-                            "reparentToDisplay");
-                    mMovedToFront = true;
-                } else if (launchStack.isActivityTypeHome()
-                        && !mTargetStack.isActivityTypeHome()) {
-                    // It is possible for the home activity to be in another stack initially.
-                    // For example, the activity may have been initially started with an intent
-                    // which placed it in the fullscreen stack. To ensure the proper handling of
-                    // the activity based on home stack assumptions, we must move it over.
-                    intentActivity.getTask().reparent(launchStack, ON_TOP,
-                            REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
-                            "reparentingHome");
+                            mStartActivity.appTimeTracker, DEFER_RESUME,
+                            "bringingFoundTaskToFront");
+                    mMovedToFront = !isSplitScreenTopStack;
+                } else {
+                    intentTask.reparent(launchStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE,
+                            DEFER_RESUME, "reparentToTargetStack");
                     mMovedToFront = true;
                 }
-
-                if (launchStack != null && launchStack.getTopMostTask() == 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);
-                    launchStack.removeIfPossible();
-                }
-
                 mOptions = null;
             }
         }
@@ -2392,7 +2388,7 @@
     private void setNewTask(Task taskToAffiliate) {
         final boolean toTop = !mLaunchTaskBehind && !mAvoidMoveToFront;
         final Task task = mTargetStack.createTask(
-                mSupervisor.getNextTaskIdForUserLocked(mStartActivity.mUserId),
+                mSupervisor.getNextTaskIdForUser(mStartActivity.mUserId),
                 mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
                 mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
                 mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions);
@@ -2469,90 +2465,6 @@
         return launchFlags;
     }
 
-    private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, int launchFlags,
-            ActivityOptions aOptions) {
-        final Task task = r.getTask();
-        ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions);
-        if (stack != null) {
-            return stack;
-        }
-
-        final ActivityStack currentStack = task != null ? task.getStack() : null;
-        final ActivityStack focusedStack = mRootWindowContainer.getTopDisplayFocusedStack();
-        if (currentStack != null) {
-            if (focusedStack != currentStack) {
-                if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
-                        "computeStackFocus: Setting " + "focused stack to r=" + r
-                                + " task=" + task);
-            } else {
-                if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
-                        "computeStackFocus: Focused stack already=" + focusedStack);
-            }
-            return currentStack;
-        }
-
-        if (canLaunchIntoFocusedStack(r, newTask)) {
-            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
-                    "computeStackFocus: Have a focused stack=" + focusedStack);
-            return focusedStack;
-        }
-
-        if (mPreferredDisplayId != DEFAULT_DISPLAY) {
-            // Try to put the activity in a stack on a secondary display.
-            stack = mRootWindowContainer.getValidLaunchStackOnDisplay(
-                    mPreferredDisplayId, r, aOptions, mLaunchParams);
-            if (stack == null) {
-                // If source display is not suitable - look for topmost valid stack in the system.
-                if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
-                        "computeStackFocus: Can't launch on mPreferredDisplayId="
-                                + mPreferredDisplayId + ", looking on all displays.");
-                stack = mRootWindowContainer.getNextValidLaunchStack(r, mPreferredDisplayId);
-            }
-        }
-        if (stack == null) {
-            stack = mRootWindowContainer.getLaunchStack(r, aOptions, task, ON_TOP);
-        }
-        if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
-                + r + " stackId=" + stack.mStackId);
-        return stack;
-    }
-
-    /** Check if provided activity record can launch in currently focused stack. */
-    // TODO: This method can probably be consolidated into getLaunchStack() below.
-    private boolean canLaunchIntoFocusedStack(ActivityRecord r, boolean newTask) {
-        final ActivityStack focusedStack = mRootWindowContainer.getTopDisplayFocusedStack();
-        final boolean canUseFocusedStack;
-        if (focusedStack.isActivityTypeAssistant()) {
-            canUseFocusedStack = r.isActivityTypeAssistant();
-        } else {
-            switch (focusedStack.getWindowingMode()) {
-                case WINDOWING_MODE_FULLSCREEN:
-                    // The fullscreen stack can contain any task regardless of if the task is
-                    // resizeable or not. So, we let the task go in the fullscreen task if it is the
-                    // focus stack.
-                    canUseFocusedStack = true;
-                    break;
-                case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
-                case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY:
-                    // Any activity which supports split screen can go in the docked stack.
-                    canUseFocusedStack = r.supportsSplitScreenWindowingMode();
-                    break;
-                case WINDOWING_MODE_FREEFORM:
-                    // Any activity which supports freeform can go in the freeform stack.
-                    canUseFocusedStack = r.supportsFreeform();
-                    break;
-                default:
-                    // Dynamic stacks behave similarly to the fullscreen stack and can contain any
-                    // resizeable task.
-                    canUseFocusedStack = !focusedStack.isOnHomeDisplay()
-                            && r.canBeLaunchedOnDisplay(focusedStack.mDisplayId);
-            }
-        }
-        return canUseFocusedStack && !newTask
-                // Using the focus stack isn't important enough to override the preferred display.
-                && (mPreferredDisplayId == focusedStack.mDisplayId);
-    }
-
     private ActivityStack getLaunchStack(ActivityRecord r, int launchFlags, Task task,
             ActivityOptions aOptions) {
         // We are reusing a task, keep the stack!
@@ -2560,53 +2472,10 @@
             return mReuseTask.getStack();
         }
 
-        if (((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0)
-                 || mPreferredDisplayId != DEFAULT_DISPLAY) {
-            final boolean onTop =
-                    (aOptions == null || !aOptions.getAvoidMoveToFront()) && !mLaunchTaskBehind;
-            final ActivityStack stack =
-                    mRootWindowContainer.getLaunchStack(r, aOptions, task, onTop, mLaunchParams,
-                            mRequest.realCallingPid, mRequest.realCallingUid);
-            return stack;
-        }
-        // Otherwise handle adjacent launch.
-
-        final ActivityStack focusedStack = mRootWindowContainer.getTopDisplayFocusedStack();
-        // The parent activity doesn't want to launch the activity on top of itself, but
-        // instead tries to put it onto other side in side-by-side mode.
-        final ActivityStack parentStack = task != null ? task.getStack(): focusedStack;
-
-        if (parentStack != focusedStack) {
-            // If task's parent stack is not focused - use it during adjacent launch.
-            return parentStack;
-        } else {
-            if (focusedStack != null && task == focusedStack.getTopMostTask()) {
-                // If task is already on top of focused stack - use it. We don't want to move the
-                // existing focused task to adjacent stack, just deliver new intent in this case.
-                return focusedStack;
-            }
-
-            if (parentStack != null && parentStack.inSplitScreenPrimaryWindowingMode()) {
-                // If parent was in docked stack, the natural place to launch another activity
-                // will be fullscreen, so it can appear alongside the docked window.
-                final int activityType =
-                        mRootWindowContainer.resolveActivityType(r, mOptions, task);
-                return parentStack.getDisplay().getOrCreateStack(
-                        WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, activityType, ON_TOP);
-            } else {
-                // If the parent is not in the docked stack, we check if there is docked window
-                // and if yes, we will launch into that stack. If not, we just put the new
-                // activity into parent's stack, because we can't find a better place.
-                final ActivityStack dockedStack =
-                        mRootWindowContainer.getDefaultDisplay().getSplitScreenPrimaryStack();
-                if (dockedStack != null && !dockedStack.shouldBeVisible(r)) {
-                    // There is a docked stack, but it isn't visible, so we can't launch into that.
-                    return mRootWindowContainer.getLaunchStack(r, aOptions, task, ON_TOP);
-                } else {
-                    return dockedStack;
-                }
-            }
-        }
+        final boolean onTop =
+                (aOptions == null || !aOptions.getAvoidMoveToFront()) && !mLaunchTaskBehind;
+        return mRootWindowContainer.getLaunchStack(r, aOptions, task, onTop, mLaunchParams,
+                mRequest.realCallingPid, mRequest.realCallingUid);
     }
 
     private boolean isLaunchModeOneOf(int mode1, int mode2) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index ac1dbc4..76c0e4e 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -296,6 +296,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -901,7 +902,7 @@
 
     boolean hasSystemAlertWindowPermission(int callingUid, int callingPid, String callingPackage) {
         final int mode = getAppOpsService().noteOperation(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
-                callingUid, callingPackage, /* featureId */ null);
+                callingUid, callingPackage, /* featureId */ null, false, "");
         if (mode == AppOpsManager.MODE_DEFAULT) {
             return checkPermission(Manifest.permission.SYSTEM_ALERT_WINDOW, callingPid, callingUid)
                     == PERMISSION_GRANTED;
@@ -1684,20 +1685,16 @@
     public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
         final long origId = Binder.clearCallingIdentity();
         try {
-            WindowProcessController proc = null;
             synchronized (mGlobalLock) {
                 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityIdle");
-                ActivityStack stack = ActivityRecord.getStackLocked(token);
-                if (stack == null) {
+                final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+                if (r == null) {
                     return;
                 }
-                final ActivityRecord r = mStackSupervisor.activityIdleInternalLocked(token,
-                        false /* fromTimeout */, false /* processPausingActivities */, config);
-                if (r != null) {
-                    proc = r.app;
-                }
-                if (stopProfiling && proc != null) {
-                    proc.clearProfilerIfNeeded();
+                mStackSupervisor.activityIdleInternal(r, false /* fromTimeout */,
+                        false /* processPausingActivities */, config);
+                if (stopProfiling && r.hasProcess()) {
+                    r.app.clearProfilerIfNeeded();
                 }
             }
         } finally {
@@ -2042,8 +2039,8 @@
     public int getDisplayId(IBinder activityToken) throws RemoteException {
         synchronized (mGlobalLock) {
             final ActivityStack stack = ActivityRecord.getStackLocked(activityToken);
-            if (stack != null && stack.mDisplayId != INVALID_DISPLAY) {
-                return stack.mDisplayId;
+            if (stack != null && stack.getDisplayId() != INVALID_DISPLAY) {
+                return stack.getDisplayId();
             }
             return DEFAULT_DISPLAY;
         }
@@ -3201,7 +3198,7 @@
 
                 final ActivityStack stack = r.getActivityStack();
                 final Task task = stack.createTask(
-                        mStackSupervisor.getNextTaskIdForUserLocked(r.mUserId), ainfo, intent,
+                        mStackSupervisor.getNextTaskIdForUser(r.mUserId), ainfo, intent,
                         null /* voiceSession */, null /* voiceInteractor */, !ON_TOP);
                 if (!mRecentTasks.addToBottom(task)) {
                     // The app has too many tasks already and we can't add any more
@@ -4311,7 +4308,7 @@
 
         if (params.hasSetAspectRatio()
                 && !mWindowManager.isValidPictureInPictureAspectRatio(
-                        r.getActivityStack().mDisplayId, params.getAspectRatio())) {
+                        r.getDisplayId(), params.getAspectRatio())) {
             final float minAspectRatio = mContext.getResources().getFloat(
                     com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
             final float maxAspectRatio = mContext.getResources().getFloat(
@@ -6164,7 +6161,7 @@
     final class LocalService extends ActivityTaskManagerInternal {
         @Override
         public SleepToken acquireSleepToken(String tag, int displayId) {
-            Preconditions.checkNotNull(tag);
+            Objects.requireNonNull(tag);
             return ActivityTaskManagerService.this.acquireSleepToken(tag, displayId);
         }
 
@@ -6221,7 +6218,7 @@
         @Override
         public int startActivitiesAsPackage(String packageName, int userId, Intent[] intents,
                 Bundle bOptions) {
-            Preconditions.checkNotNull(intents, "intents");
+            Objects.requireNonNull(intents, "intents");
             final String[] resolvedTypes = new String[intents.length];
 
             // UID of the package on user userId.
@@ -6904,7 +6901,7 @@
                 if (mRootWindowContainer.finishDisabledPackageActivities(
                         packageName, disabledClasses, true, false, userId) && booted) {
                     mRootWindowContainer.resumeFocusedStacksTopActivities();
-                    mStackSupervisor.scheduleIdleLocked();
+                    mStackSupervisor.scheduleIdle();
                 }
 
                 // Clean-up disabled tasks
@@ -6931,7 +6928,7 @@
             synchronized (mGlobalLock) {
                 mRootWindowContainer.resumeFocusedStacksTopActivities();
                 if (scheduleIdle) {
-                    mStackSupervisor.scheduleIdleLocked();
+                    mStackSupervisor.scheduleIdle();
                 }
             }
         }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 51742b9..67fe149 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -230,7 +230,6 @@
 import com.android.internal.util.function.pooled.PooledFunction;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.internal.util.function.pooled.PooledPredicate;
-import com.android.server.AnimationThread;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.protolog.common.ProtoLog;
 import com.android.server.wm.utils.DisplayRotationUtil;
@@ -600,11 +599,6 @@
 
     private final SparseArray<ShellRoot> mShellRoots = new SparseArray<>();
 
-    /**
-     * Counter for next free stack ID to use for dynamic activity stacks. Unique across displays.
-     */
-    private static int sNextFreeStackId = 0;
-
     private RootWindowContainer mRootWindowContainer;
 
     /**
@@ -982,7 +976,7 @@
 
         AnimationHandler animationHandler = new AnimationHandler();
         mBoundsAnimationController = new BoundsAnimationController(mWmService.mContext,
-                mAppTransition, AnimationThread.getHandler(), animationHandler);
+                mAppTransition, mWmService.mAnimationHandler, animationHandler);
 
         final InputChannel inputChannel = mWmService.mInputManager.monitorInput(
                 "PointerEventDispatcher" + mDisplayId, mDisplayId);
@@ -5694,7 +5688,7 @@
 
     @VisibleForTesting
     int getNextStackId() {
-        return sNextFreeStackId++;
+        return mAtmService.mStackSupervisor.getNextTaskIdForUser();
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index d5f403f..999aab9 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -37,6 +37,7 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.wm.WindowManagerInternal.IDragDropCallback;
 
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
@@ -74,7 +75,7 @@
     }
 
     void registerCallback(IDragDropCallback callback) {
-        Preconditions.checkNotNull(callback);
+        Objects.requireNonNull(callback);
         mCallback.set(callback);
     }
 
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index e74f61d..55f5e28 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -156,7 +156,8 @@
             // determined individually unlike other stacks where the visibility or fullscreen
             // status of an activity in a previous task affects other.
             mBehindFullscreenActivity = !mContainerShouldBeVisible;
-        } else if (mContiner.isActivityTypeHome()) {
+        } else if (!mBehindFullscreenActivity && mContiner.isActivityTypeHome()
+                && r.isRootOfTask()) {
             if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Home task: at " + mContiner
                     + " stackShouldBeVisible=" + mContainerShouldBeVisible
                     + " behindFullscreenActivity=" + mBehindFullscreenActivity);
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index b9a9c12..a8ff500 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -47,7 +47,6 @@
 import android.view.InputWindowHandle;
 import android.view.SurfaceControl;
 
-import com.android.server.AnimationThread;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.protolog.common.ProtoLog;
 
@@ -157,7 +156,7 @@
         mDisplayContent = mService.mRoot.getDisplayContent(displayId);
         mDisplayId = displayId;
         mInputTransaction = mService.mTransactionFactory.get();
-        mHandler = AnimationThread.getHandler();
+        mHandler = mService.mAnimationHandler;
         mUpdateInputForAllWindowsConsumer = new UpdateInputForAllWindowsConsumer();
     }
 
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index 0beae7e..f4e608e 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -222,9 +222,7 @@
 
     private boolean saveTaskToLaunchParam(Task task, PersistableLaunchParams params) {
         final ActivityStack stack = task.getStack();
-        final int displayId = stack.mDisplayId;
-        final DisplayContent display =
-                mSupervisor.mRootWindowContainer.getDisplayContent(displayId);
+        final DisplayContent display = stack.getDisplayContent();
         final DisplayInfo info = new DisplayInfo();
         display.mDisplay.getDisplayInfo(info);
 
diff --git a/services/core/java/com/android/server/wm/PendingRemoteAnimationRegistry.java b/services/core/java/com/android/server/wm/PendingRemoteAnimationRegistry.java
index dcb9a6a..3b8631a 100644
--- a/services/core/java/com/android/server/wm/PendingRemoteAnimationRegistry.java
+++ b/services/core/java/com/android/server/wm/PendingRemoteAnimationRegistry.java
@@ -22,12 +22,10 @@
 import android.util.ArrayMap;
 import android.view.RemoteAnimationAdapter;
 
-import com.android.server.am.ActivityManagerService;
-
 /**
  * Registry to keep track of remote animations to be run for activity starts from a certain package.
  *
- * @see ActivityManagerService#registerRemoteAnimationForNextActivityStart
+ * @see ActivityTaskManagerService#registerRemoteAnimationForNextActivityStart
  */
 class PendingRemoteAnimationRegistry {
 
@@ -35,10 +33,10 @@
 
     private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
     private final Handler mHandler;
-    private final ActivityTaskManagerService mService;
+    private final WindowManagerGlobalLock mLock;
 
-    PendingRemoteAnimationRegistry(ActivityTaskManagerService service, Handler handler) {
-        mService = service;
+    PendingRemoteAnimationRegistry(WindowManagerGlobalLock lock, Handler handler) {
+        mLock = lock;
         mHandler = handler;
     }
 
@@ -76,7 +74,7 @@
             this.packageName = packageName;
             this.adapter = adapter;
             mHandler.postDelayed(() -> {
-                synchronized (mService.mGlobalLock) {
+                synchronized (mLock) {
                     final Entry entry = mEntries.get(packageName);
                     if (entry == this) {
                         mEntries.remove(packageName);
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index a18d541..5df80fc 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1382,7 +1382,7 @@
 
         // Ignore tasks from different displays
         // TODO (b/115289124): No Recents on non-default displays.
-        if (stack.mDisplayId != DEFAULT_DISPLAY) {
+        if (stack.getDisplayId() != DEFAULT_DISPLAY) {
             return false;
         }
 
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index f78c82b..a5c90a1 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -37,8 +37,8 @@
 /** Helper class for processing the reset of a task. */
 class ResetTargetTaskHelper {
     private Task mTask;
-    private ActivityStack mParent;
     private Task mTargetTask;
+    private ActivityStack mTargetStack;
     private ActivityRecord mRoot;
     private boolean mForceReset;
     private boolean mCanMoveOptions;
@@ -47,7 +47,7 @@
     private ActivityOptions mTopOptions;
     private ArrayList<ActivityRecord> mResultActivities = new ArrayList<>();
     private ArrayList<ActivityRecord> mAllActivities = new ArrayList<>();
-    private ArrayList<Task> mCreatedTasks = new ArrayList<>();
+    private ArrayList<ActivityRecord> mPendingReparentActivities = new ArrayList<>();
 
     private void reset(Task task) {
         mTask = task;
@@ -56,23 +56,22 @@
         mTopOptions = null;
         mResultActivities.clear();
         mAllActivities.clear();
-        mCreatedTasks.clear();
     }
 
-    ActivityOptions process(ActivityStack parent, Task targetTask, boolean forceReset) {
-        mParent = parent;
+    ActivityOptions process(Task targetTask, boolean forceReset) {
         mForceReset = forceReset;
         mTargetTask = targetTask;
         mTargetTaskFound = false;
+        mTargetStack = targetTask.getStack();
         mActivityReparentPosition = -1;
 
         final PooledConsumer c = PooledLambda.obtainConsumer(
                 ResetTargetTaskHelper::processTask, this, PooledLambda.__(Task.class));
-        parent.forAllTasks(c);
+        targetTask.mWmService.mRoot.forAllTasks(c);
         c.recycle();
 
+        processPendingReparentActivities();
         reset(null);
-        mParent = null;
         return mTopOptions;
     }
 
@@ -89,14 +88,9 @@
                 PooledLambda.__(ActivityRecord.class), isTargetTask);
         task.forAllActivities(f);
         f.recycle();
-
-        processCreatedTasks();
     }
 
     private boolean processActivity(ActivityRecord r, boolean isTargetTask) {
-        // End processing if we have reached the root.
-        if (r == mRoot) return true;
-
         mAllActivities.add(r);
         final int flags = r.info.flags;
         final boolean finishOnTaskLaunch =
@@ -122,32 +116,9 @@
                     // it out of here. We will move it as far out of the way as possible, to the
                     // bottom of the activity stack. This also keeps it correctly ordered with
                     // any activities we previously moved.
-                    // TODO: We should probably look for other stacks also, since corresponding
-                    //  task with the same affinity is unlikely to be in the same stack.
-                    final Task targetTask;
-                    final ActivityRecord bottom = mParent.getBottomMostActivity();
 
-                    if (bottom != null && r.taskAffinity.equals(bottom.getTask().affinity)) {
-                        // If the activity currently at the bottom has the same task affinity as
-                        // the one we are moving, then merge it into the same task.
-                        targetTask = bottom.getTask();
-                        if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity "
-                                + r + " out to bottom task " + targetTask);
-                    } else {
-                        targetTask = mParent.createTask(
-                                mParent.mStackSupervisor.getNextTaskIdForUserLocked(r.mUserId),
-                                r.info, null /* intent */, null /* voiceSession */,
-                                null /* voiceInteractor */, false /* toTop */);
-                        targetTask.affinityIntent = r.intent;
-                        mCreatedTasks.add(targetTask);
-                        if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity "
-                                + r + " out to new task " + targetTask);
-                    }
-
-                    mResultActivities.add(r);
-                    processResultActivities(r, targetTask, 0 /*bottom*/, true, true);
-                    mParent.positionChildAtBottom(targetTask);
-                    mParent.mStackSupervisor.mRecentTasks.add(targetTask);
+                    // Handle this activity after we have done traversing the hierarchy.
+                    mPendingReparentActivities.add(r);
                     return false;
                 }
             }
@@ -203,8 +174,6 @@
                 processResultActivities(
                         r, mTargetTask, mActivityReparentPosition, false, false);
 
-                mParent.positionChildAtTop(mTargetTask);
-
                 // Now we've moved it in to place...but what if this is a singleTop activity and
                 // we have put it on top of another instance of the same activity? Then we drop
                 // the instance below so it remains singleTop.
@@ -255,23 +224,51 @@
         }
     }
 
-    private void processCreatedTasks() {
-        if (mCreatedTasks.isEmpty()) return;
-
-        DisplayContent display = mParent.getDisplay();
-        final boolean singleTaskInstanceDisplay = display.isSingleTaskInstance();
-        if (singleTaskInstanceDisplay) {
-            display = mParent.mRootWindowContainer.getDefaultDisplay();
+    private void processPendingReparentActivities() {
+        if (mPendingReparentActivities.isEmpty()) {
+            return;
         }
 
-        final int windowingMode = mParent.getWindowingMode();
-        final int activityType = mParent.getActivityType();
+        final ActivityTaskManagerService atmService = mTargetStack.mAtmService;
+        final ArrayList<Task> createdTasks = new ArrayList<>();
+        while (!mPendingReparentActivities.isEmpty()) {
+            final ActivityRecord r = mPendingReparentActivities.remove(0);
+            final ActivityRecord bottom = mTargetStack.getBottomMostActivity();
+            final Task targetTask;
+            if (bottom != null && r.taskAffinity.equals(bottom.getTask().affinity)) {
+                // If the activity currently at the bottom has the same task affinity as
+                // the one we are moving, then merge it into the same task.
+                targetTask = bottom.getTask();
+                if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity "
+                        + r + " out to bottom task " + targetTask);
+            } else {
+                targetTask = mTargetStack.createTask(
+                        atmService.mStackSupervisor.getNextTaskIdForUser(r.mUserId), r.info,
+                        null /* intent */, null /* voiceSession */, null /* voiceInteractor */,
+                        false /* toTop */);
+                targetTask.affinityIntent = r.intent;
+                createdTasks.add(targetTask);
+                if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity "
+                        + r + " out to new task " + targetTask);
+            }
+            r.reparent(targetTask, 0 /* position */, "resetTargetTaskIfNeeded");
+            atmService.mStackSupervisor.mRecentTasks.add(targetTask);
+        }
+
+        DisplayContent display = mTargetStack.getDisplay();
+        final boolean singleTaskInstanceDisplay = display.isSingleTaskInstance();
+        if (singleTaskInstanceDisplay) {
+            display = atmService.mRootWindowContainer.getDefaultDisplay();
+        }
+
+        final int windowingMode = mTargetStack.getWindowingMode();
+        final int activityType = mTargetStack.getActivityType();
         if (!singleTaskInstanceDisplay && !display.alwaysCreateStack(windowingMode, activityType)) {
             return;
         }
 
-        while (!mCreatedTasks.isEmpty()) {
-            final Task targetTask = mCreatedTasks.remove(mCreatedTasks.size() - 1);
+        while (!createdTasks.isEmpty()) {
+            final Task targetTask = createdTasks.remove(createdTasks.size() - 1);
             final ActivityStack targetStack = display.getOrCreateStack(
                     windowingMode, activityType, false /* onTop */);
             targetTask.reparent(targetStack, false /* toTop */, REPARENT_LEAVE_STACK_IN_PLACE,
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 5470327..704ab67 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1495,7 +1495,7 @@
         // Fallback to top focused display if the displayId is invalid.
         if (displayId == INVALID_DISPLAY) {
             final ActivityStack stack = getTopDisplayFocusedStack();
-            displayId = stack != null ? stack.mDisplayId : DEFAULT_DISPLAY;
+            displayId = stack != null ? stack.getDisplayId() : DEFAULT_DISPLAY;
         }
 
         Intent homeIntent = null;
@@ -2148,7 +2148,7 @@
                 // ensures that all the necessary work to migrate states in the old and new stacks
                 // is also done.
                 final Task newTask = task.getStack().createTask(
-                        mStackSupervisor.getNextTaskIdForUserLocked(r.mUserId), r.info,
+                        mStackSupervisor.getNextTaskIdForUser(r.mUserId), r.info,
                         r.intent, null, null, true);
                 r.reparent(newTask, MAX_VALUE, "moveActivityToStack");
 
@@ -2405,11 +2405,10 @@
     }
 
     private ActivityManager.StackInfo getStackInfo(ActivityStack stack) {
-        final int displayId = stack.mDisplayId;
-        final DisplayContent display = getDisplayContent(displayId);
+        final DisplayContent display = stack.getDisplayContent();
         ActivityManager.StackInfo info = new ActivityManager.StackInfo();
         stack.getBounds(info.bounds);
-        info.displayId = displayId;
+        info.displayId = display.mDisplayId;
         info.stackId = stack.mStackId;
         info.stackToken = stack.mRemoteToken;
         info.userId = stack.mCurrentUser;
@@ -2571,7 +2570,7 @@
     }
 
     ActivityStack findStackBehind(ActivityStack stack) {
-        final DisplayContent display = getDisplayContent(stack.mDisplayId);
+        final DisplayContent display = getDisplayContent(stack.getDisplayId());
         if (display != null) {
             for (int i = display.getStackCount() - 1; i >= 0; i--) {
                 if (display.getStackAt(i) == stack && i > 0) {
@@ -2806,7 +2805,6 @@
             int realCallingUid) {
         int taskId = INVALID_TASK_ID;
         int displayId = INVALID_DISPLAY;
-        //Rect bounds = null;
 
         // We give preference to the launch preference in activity options.
         if (options != null) {
@@ -2828,7 +2826,7 @@
         }
 
         final int activityType = resolveActivityType(r, options, candidateTask);
-        ActivityStack stack;
+        ActivityStack stack = null;
 
         // Next preference for stack goes to the display Id set the candidate display.
         if (launchParams != null && launchParams.mPreferredDisplayId != INVALID_DISPLAY) {
@@ -2861,7 +2859,6 @@
 
         // Give preference to the stack and display of the input task and activity if they match the
         // mode we want to launch into.
-        stack = null;
         DisplayContent display = null;
         if (candidateTask != null) {
             stack = candidateTask.getStack();
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index bbd986f..50cea2e 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -27,6 +27,7 @@
 import android.animation.ValueAnimator;
 import android.annotation.Nullable;
 import android.hardware.power.V1_0.PowerHint;
+import android.os.Handler;
 import android.os.PowerManagerInternal;
 import android.util.ArrayMap;
 import android.view.Choreographer;
@@ -57,6 +58,8 @@
     @VisibleForTesting
     Choreographer mChoreographer;
 
+    private final Handler mAnimationThreadHandler = AnimationThread.getHandler();
+    private final Handler mSurfaceAnimationHandler = SurfaceAnimationThread.getHandler();
     private final Runnable mApplyTransactionRunnable = this::applyTransaction;
     private final AnimationHandler mAnimationHandler;
     private final Transaction mFrameTransaction;
@@ -85,7 +88,7 @@
     SurfaceAnimationRunner(@Nullable AnimationFrameCallbackProvider callbackProvider,
             AnimatorFactory animatorFactory, Transaction frameTransaction,
             PowerManagerInternal powerManagerInternal) {
-        SurfaceAnimationThread.getHandler().runWithScissors(() -> mChoreographer = getSfInstance(),
+        mSurfaceAnimationHandler.runWithScissors(() -> mChoreographer = getSfInstance(),
                 0 /* timeout */);
         mFrameTransaction = frameTransaction;
         mAnimationHandler = new AnimationHandler();
@@ -152,7 +155,7 @@
                 synchronized (mCancelLock) {
                     anim.mCancelled = true;
                 }
-                SurfaceAnimationThread.getHandler().post(() -> {
+                mSurfaceAnimationHandler.post(() -> {
                     anim.mAnim.cancel();
                     applyTransaction();
                 });
@@ -211,7 +214,7 @@
                         if (!a.mCancelled) {
 
                             // Post on other thread that we can push final state without jank.
-                            AnimationThread.getHandler().post(a.mFinishCallback);
+                            mAnimationThreadHandler.post(a.mFinishCallback);
                         }
                     }
                 }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 987ecc5..914b95c 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -54,6 +54,7 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
 import static android.view.SurfaceControl.METADATA_TASK_ID;
 
 import static com.android.server.am.TaskRecordProto.ACTIVITIES;
@@ -127,7 +128,6 @@
 import android.util.DisplayMetrics;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
-import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.RemoteAnimationTarget;
 import android.view.Surface;
@@ -268,9 +268,6 @@
 
     int mLockTaskUid = -1;  // The uid of the application that called startLockTask().
 
-    /** Current stack. Setter must always be used to update the value. */
-    private ActivityStack mStack;
-
     /** The process that had previously hosted the root activity of this task.
      * Used to know that we should try harder to keep this process around, in case the
      * user wants to return to it. */
@@ -346,7 +343,7 @@
     private final Rect mOverrideDisplayedBounds = new Rect();
 
     /** ID of the display which rotation {@link #mRotation} has. */
-    private int mLastRotationDisplayId = Display.INVALID_DISPLAY;
+    private int mLastRotationDisplayId = INVALID_DISPLAY;
     /**
      * Display rotation as of the last time {@link #setBounds(Rect)} was called or this task was
      * moved to a new display.
@@ -388,6 +385,8 @@
 
     private static Exception sTmpException;
 
+    private boolean mForceShowForAllUsers;
+
     private final FindRootHelper mFindRootHelper = new FindRootHelper();
     private class FindRootHelper {
         private ActivityRecord mRoot;
@@ -678,7 +677,7 @@
         if (toStack == sourceStack) {
             return false;
         }
-        if (!canBeLaunchedOnDisplay(toStack.mDisplayId)) {
+        if (!canBeLaunchedOnDisplay(toStack.getDisplayId())) {
             return false;
         }
 
@@ -959,10 +958,6 @@
         mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.mTaskId;
     }
 
-    ActivityStack getStack() {
-        return mStack;
-    }
-
     @Override
     void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
         final ActivityStack oldStack = ((ActivityStack) oldParent);
@@ -973,8 +968,6 @@
             cleanUpResourcesForDestroy();
         }
 
-        mStack = newStack;
-
         super.onParentChanged(newParent, oldParent);
 
         if (oldStack != null) {
@@ -1044,13 +1037,6 @@
         mAtmService.mRootWindowContainer.invalidateTaskLayers();
     }
 
-    /**
-     * @return Id of current stack, {@link ActivityTaskManager#INVALID_STACK_ID} if no stack is set.
-     */
-    int getStackId() {
-        return mStack != null ? mStack.mStackId : INVALID_STACK_ID;
-    }
-
     // Close up recents linked list.
     private void closeRecentsChain() {
         if (mPrevAffiliate != null) {
@@ -1261,7 +1247,7 @@
             }
         } else if (!mReuseTask) {
             // Remove entire task if it doesn't have any activity left and it isn't marked for reuse
-            mStack.removeChild(this, reason);
+            getStack().removeChild(this, reason);
             EventLogTags.writeWmTaskRemoved(mTaskId,
                     "removeChild: last r=" + r + " in t=" + this);
             removeIfPossible();
@@ -1278,9 +1264,9 @@
             return false;
         }
         if (includeFinishing) {
-            return getActivity((r) -> r.mTaskOverlay) != null;
+            return getActivity((r) -> r.isTaskOverlay()) != null;
         }
-        return getActivity((r) -> !r.finishing && r.mTaskOverlay) != null;
+        return getActivity((r) -> !r.finishing && r.isTaskOverlay()) != null;
     }
 
     private boolean autoRemoveFromRecents() {
@@ -1296,7 +1282,7 @@
      */
     private void performClearTaskAtIndexLocked(String reason) {
         // Broken down into to cases to avoid object create due to capturing mStack.
-        if (mStack == null) {
+        if (getStack() == null) {
             forAllActivities((r) -> {
                 if (r.finishing) return;
                 // Task was restored from persistent storage.
@@ -1525,7 +1511,7 @@
 
     private static boolean setTaskDescriptionFromActivityAboveRoot(
             ActivityRecord r, ActivityRecord root, TaskDescription td) {
-        if (!r.mTaskOverlay && r.taskDescription != null) {
+        if (!r.isTaskOverlay() && r.taskDescription != null) {
             final TaskDescription atd = r.taskDescription;
             if (td.getLabel() == null) {
                 td.setLabel(atd.getLabel());
@@ -1579,11 +1565,10 @@
         // If the task has no requested minimal size, we'd like to enforce a minimal size
         // so that the user can not render the task too small to manipulate. We don't need
         // to do this for the pinned stack as the bounds are controlled by the system.
-        if (!inPinnedWindowingMode() && mStack != null) {
+        if (!inPinnedWindowingMode() && getDisplayContent() != null) {
             final int defaultMinSizeDp =
                     mAtmService.mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp;
-            final DisplayContent display =
-                    mAtmService.mRootWindowContainer.getDisplayContent(mStack.mDisplayId);
+            final DisplayContent display = getDisplayContent();
             final float density =
                     (float) display.getConfiguration().densityDpi / DisplayMetrics.DENSITY_DEFAULT;
             final int defaultMinSize = (int) (defaultMinSizeDp * density);
@@ -1820,7 +1805,7 @@
      * @param bounds bounds to calculate smallestwidthdp for.
      */
     private int getSmallestScreenWidthDpForDockedBounds(Rect bounds) {
-        DisplayContent dc = mStack.getDisplay().mDisplayContent;
+        DisplayContent dc = getDisplayContent();
         if (dc != null) {
             return dc.getDockedDividerController().getSmallestWidthDpForBounds(bounds);
         }
@@ -1884,9 +1869,9 @@
             if (insideParentBounds && WindowConfiguration.isFloating(windowingMode)) {
                 mTmpNonDecorBounds.set(mTmpFullBounds);
                 mTmpStableBounds.set(mTmpFullBounds);
-            } else if (insideParentBounds && mStack != null) {
+            } else if (insideParentBounds && getDisplayContent() != null) {
                 final DisplayInfo di = new DisplayInfo();
-                mStack.getDisplay().mDisplay.getDisplayInfo(di);
+                getDisplayContent().mDisplay.getDisplayInfo(di);
 
                 // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen
                 // area, i.e. the screen area without the system bars.
@@ -1997,7 +1982,7 @@
                     ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;
             final Rect parentBounds =
                     new Rect(newParentConfig.windowConfiguration.getBounds());
-            final DisplayContent display = mStack.getDisplay();
+            final DisplayContent display = getDisplayContent();
             if (display != null && display.mDisplayContent != null) {
                 // If a freeform window moves below system bar, there is no way to move it again
                 // by touch. Because its caption is covered by system bar. So we exclude them
@@ -2077,7 +2062,8 @@
     /** Updates the task's bounds and override configuration to match what is expected for the
      * input stack. */
     void updateOverrideConfigurationForStack(ActivityStack inStack) {
-        if (mStack != null && mStack == inStack) {
+        final ActivityStack stack = getStack();
+        if (stack != null && stack == inStack) {
             return;
         }
 
@@ -2101,7 +2087,8 @@
 
     /** Returns the bounds that should be used to launch this task. */
     Rect getLaunchBounds() {
-        if (mStack == null) {
+        final ActivityStack stack = getStack();
+        if (stack == null) {
             return null;
         }
 
@@ -2109,9 +2096,9 @@
         if (!isActivityTypeStandardOrUndefined()
                 || windowingMode == WINDOWING_MODE_FULLSCREEN
                 || (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !isResizeable())) {
-            return isResizeable() ? mStack.getRequestedOverrideBounds() : null;
+            return isResizeable() ? stack.getRequestedOverrideBounds() : null;
         } else if (!getWindowConfiguration().persistTaskBounds()) {
-            return mStack.getRequestedOverrideBounds();
+            return stack.getRequestedOverrideBounds();
         }
         return mLastNonFullscreenBounds;
     }
@@ -2134,19 +2121,32 @@
 
     @Override
     DisplayContent getDisplayContent() {
-        return getTaskStack() != null ? getTaskStack().getDisplayContent() : null;
+        return getStack() != null ? getStack().getDisplayContent() : null;
     }
 
-    ActivityStack getTaskStack() {
+    int getDisplayId() {
+        final DisplayContent dc = getDisplayContent();
+        return dc != null ? dc.mDisplayId : INVALID_DISPLAY;
+    }
+
+    ActivityStack getStack() {
         return (ActivityStack) getParent();
     }
 
+    /**
+     * @return Id of current stack, {@link ActivityTaskManager#INVALID_STACK_ID} if no stack is set.
+     */
+    int getStackId() {
+        final ActivityStack stack = getStack();
+        return stack != null ? stack.mStackId : INVALID_STACK_ID;
+    }
+
     // TODO(task-hierarchy): Needs to take a generic WindowManager when task contains other tasks.
     int getAdjustedAddPosition(ActivityRecord r, int suggestedPosition) {
         int maxPosition = mChildren.size();
-        if (!r.mTaskOverlay) {
+        if (!r.isTaskOverlay()) {
             // We want to place all non-overlay activities below overlays.
-            final ActivityRecord bottomMostOverlay = getActivity((ar) -> ar.mTaskOverlay, false);
+            final ActivityRecord bottomMostOverlay = getActivity((ar) -> ar.isTaskOverlay(), false);
             if (bottomMostOverlay != null) {
                 maxPosition = Math.max(mChildren.indexOf(bottomMostOverlay) - 1, 0);
             }
@@ -2171,7 +2171,7 @@
             // No reason to defer removal of a Task that doesn't have any child.
             return false;
         }
-        return hasWindowsAlive() && getTaskStack().isAnimating(TRANSITION | CHILDREN);
+        return hasWindowsAlive() && getStack().isAnimating(TRANSITION | CHILDREN);
     }
 
     @Override
@@ -2184,10 +2184,10 @@
     // TODO: Consolidate this with Task.reparent()
     void reparent(ActivityStack stack, int position, boolean moveParents, String reason) {
         if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
-                + " from stack=" + getTaskStack());
+                + " from stack=" + getStack());
         EventLogTags.writeWmTaskRemoved(mTaskId, "reParentTask:" + reason);
 
-        position = stack.findPositionForTask(this, position, showForAllUsers());
+        position = stack.findPositionForTask(this, position);
 
         reparent(stack, position);
 
@@ -2214,8 +2214,8 @@
     @Override
     public int setBounds(Rect bounds) {
         int rotation = Surface.ROTATION_0;
-        final DisplayContent displayContent = getTaskStack() != null
-                ? getTaskStack().getDisplayContent() : null;
+        final DisplayContent displayContent = getStack() != null
+                ? getStack().getDisplayContent() : null;
         if (displayContent != null) {
             rotation = displayContent.getDisplayInfo().rotation;
         } else if (bounds == null) {
@@ -2256,7 +2256,7 @@
     void onDisplayChanged(DisplayContent dc) {
         adjustBoundsForDisplayChangeIfNeeded(dc);
         super.onDisplayChanged(dc);
-        final int displayId = (dc != null) ? dc.getDisplayId() : Display.INVALID_DISPLAY;
+        final int displayId = (dc != null) ? dc.getDisplayId() : INVALID_DISPLAY;
         mWmService.mAtmService.getTaskChangeNotificationController().notifyTaskDisplayChanged(
                 mTaskId, displayId);
     }
@@ -2401,7 +2401,7 @@
 
     /** Bounds of the task to be used for dimming, as well as touch related tests. */
     public void getDimBounds(Rect out) {
-        final DisplayContent displayContent = getTaskStack().getDisplayContent();
+        final DisplayContent displayContent = getStack().getDisplayContent();
         // It doesn't matter if we in particular are part of the resize, since we couldn't have
         // a DimLayer anyway if we weren't visible.
         final boolean dockedResizing = displayContent != null
@@ -2424,9 +2424,9 @@
             // stack bounds and so we don't even want to use them. Even if the app should not be
             // resized the Dim should keep up with the divider.
             if (dockedResizing) {
-                getTaskStack().getBounds(out);
+                getStack().getBounds(out);
             } else {
-                getTaskStack().getBounds(mTmpRect);
+                getStack().getBounds(mTmpRect);
                 mTmpRect.intersect(getBounds());
                 out.set(mTmpRect);
             }
@@ -2439,9 +2439,9 @@
     void setDragResizing(boolean dragResizing, int dragResizeMode) {
         if (mDragResizing != dragResizing) {
             // No need to check if the mode is allowed if it's leaving dragResize
-            if (dragResizing && !DragResizeMode.isModeAllowedForStack(getTaskStack(), dragResizeMode)) {
+            if (dragResizing && !DragResizeMode.isModeAllowedForStack(getStack(), dragResizeMode)) {
                 throw new IllegalArgumentException("Drag resize mode not allow for stack stackId="
-                        + getTaskStack().mStackId + " dragResizeMode=" + dragResizeMode);
+                        + getStack().mStackId + " dragResizeMode=" + dragResizeMode);
             }
             mDragResizing = dragResizing;
             mDragResizeMode = dragResizeMode;
@@ -2524,6 +2524,15 @@
         return r != null && r.mShowForAllUsers;
     }
 
+    @Override
+    boolean showToCurrentUser() {
+        return mForceShowForAllUsers || showForAllUsers() || mWmService.isCurrentProfile(mUserId);
+    }
+
+    void setForceShowForAllUsers(boolean forceShowForAllUsers) {
+        mForceShowForAllUsers = forceShowForAllUsers;
+    }
+
     /**
      * When we are in a floating stack (Freeform, Pinned, ...) we calculate
      * insets differently. However if we are animating to the fullscreen stack
@@ -2532,7 +2541,7 @@
      */
     boolean isFloating() {
         return getWindowConfiguration().tasksAreFloating()
-                && !getTaskStack().isAnimatingBoundsToFullscreen() && !mPreserveNonFloatingState;
+                && !getStack().isAnimatingBoundsToFullscreen() && !mPreserveNonFloatingState;
     }
 
     @Override
@@ -2770,7 +2779,7 @@
         info.userId = mUserId;
         info.stackId = getStackId();
         info.taskId = mTaskId;
-        info.displayId = mStack == null ? Display.INVALID_DISPLAY : mStack.mDisplayId;
+        info.displayId = getDisplayId();
         info.isRunning = getTopNonFinishingActivity() != null;
         info.baseIntent = new Intent(getBaseIntent());
         info.baseActivity = mReuseActivitiesReport.base != null
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index b8f3abe..e6757e1 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -316,8 +316,8 @@
         ActivityStack stack =
                 (displayId == INVALID_DISPLAY && task != null) ? task.getStack() : null;
         if (stack != null) {
-            if (DEBUG) appendLog("display-from-task=" + stack.mDisplayId);
-            displayId = stack.mDisplayId;
+            if (DEBUG) appendLog("display-from-task=" + stack.getDisplayId());
+            displayId = stack.getDisplayId();
         }
 
         if (displayId == INVALID_DISPLAY && source != null) {
diff --git a/services/core/java/com/android/server/wm/TaskPersister.java b/services/core/java/com/android/server/wm/TaskPersister.java
index 8cff99b..20af250 100644
--- a/services/core/java/com/android/server/wm/TaskPersister.java
+++ b/services/core/java/com/android/server/wm/TaskPersister.java
@@ -339,7 +339,7 @@
                                             + userTasksDir.getAbsolutePath());
                                 } else {
                                     // Looks fine.
-                                    mStackSupervisor.setNextTaskIdForUserLocked(taskId, userId);
+                                    mStackSupervisor.setNextTaskIdForUser(taskId, userId);
                                     task.isPersistable = true;
                                     tasks.add(task);
                                     recoveredTaskIds.add(taskId);
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 2a1d271..8bbb0d7 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -449,7 +449,7 @@
         }
 
         // This is a moving or scrolling operation.
-        mTask.getTaskStack().getDimBounds(mTmpRect);
+        mTask.getStack().getDimBounds(mTmpRect);
         // If a target window is covered by system bar, there is no way to move it again by touch.
         // So we exclude them from stack bounds. and then it will be shown inside stable area.
         Rect stableBounds = new Rect();
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index f7525a9..fd91bc5 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -32,7 +32,6 @@
 import android.view.Choreographer;
 import android.view.SurfaceControl;
 
-import com.android.server.AnimationThread;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.protolog.common.ProtoLog;
 
@@ -92,7 +91,7 @@
         mContext = service.mContext;
         mPolicy = service.mPolicy;
         mTransaction = service.mTransactionFactory.get();
-        AnimationThread.getHandler().runWithScissors(
+        service.mAnimationHandler.runWithScissors(
                 () -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */);
 
         mAnimationFrameCallback = frameTimeNs -> {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 5c02f46..5daf567 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1071,6 +1071,10 @@
         }
     }
 
+    boolean showToCurrentUser() {
+        return true;
+    }
+
     /**
      * For all windows at or below this container call the callback.
      * @param   callback Calls the {@link ToBooleanFunction#apply} method for each window found and
@@ -1323,12 +1327,12 @@
             if (includeOverlays) {
                 return getActivity((r) -> true);
             }
-            return getActivity((r) -> !r.mTaskOverlay);
+            return getActivity((r) -> !r.isTaskOverlay());
         } else if (includeOverlays) {
             return getActivity((r) -> !r.finishing);
         }
 
-        return getActivity((r) -> !r.finishing && !r.mTaskOverlay);
+        return getActivity((r) -> !r.finishing && !r.isTaskOverlay());
     }
 
     void forAllWallpaperWindows(Consumer<WallpaperWindowToken> callback) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerConstants.java b/services/core/java/com/android/server/wm/WindowManagerConstants.java
index 74d5c04..b0c5dbc 100644
--- a/services/core/java/com/android/server/wm/WindowManagerConstants.java
+++ b/services/core/java/com/android/server/wm/WindowManagerConstants.java
@@ -19,8 +19,6 @@
 import static android.provider.AndroidDeviceConfig.KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE;
 import static android.provider.AndroidDeviceConfig.KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 import android.provider.AndroidDeviceConfig;
 import android.provider.DeviceConfig;
 
@@ -28,6 +26,7 @@
 import com.android.server.wm.utils.DeviceConfigInterface;
 
 import java.io.PrintWriter;
+import java.util.Objects;
 import java.util.concurrent.Executor;
 
 /**
@@ -74,8 +73,8 @@
     WindowManagerConstants(WindowManagerGlobalLock globalLock,
             Runnable updateSystemGestureExclusionCallback,
             DeviceConfigInterface deviceConfig) {
-        mGlobalLock = checkNotNull(globalLock);
-        mUpdateSystemGestureExclusionCallback = checkNotNull(updateSystemGestureExclusionCallback);
+        mGlobalLock = Objects.requireNonNull(globalLock);
+        mUpdateSystemGestureExclusionCallback = Objects.requireNonNull(updateSystemGestureExclusionCallback);
         mDeviceConfig = deviceConfig;
         mListenerAndroid = this::onAndroidPropertiesChanged;
         mListenerWindowManager = this::onWindowPropertiesChanged;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 53c5ebd..223e9b9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -255,7 +255,6 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.LatencyTracker;
-import com.android.internal.util.Preconditions;
 import com.android.internal.util.function.pooled.PooledConsumer;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.internal.view.WindowManagerPolicyThread;
@@ -296,6 +295,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.function.Function;
 import java.util.function.Supplier;
 
@@ -1507,7 +1507,6 @@
             final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
             displayPolicy.adjustWindowParamsLw(win, win.mAttrs, Binder.getCallingPid(),
                     Binder.getCallingUid());
-            win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
 
             res = displayPolicy.validateAddingWindowLw(attrs);
             if (res != WindowManagerGlobal.ADD_OKAY) {
@@ -2864,7 +2863,7 @@
             != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires DISABLE_KEYGUARD permission");
         }
-        Preconditions.checkNotNull(token, "token is null");
+        Objects.requireNonNull(token, "token is null");
         final int callingUid = Binder.getCallingUid();
         final long origIdentity = Binder.clearCallingIdentity();
         try {
@@ -3174,7 +3173,7 @@
     }
 
     /* Called by WindowState */
-    boolean isCurrentProfileLocked(int userId) {
+    boolean isCurrentProfile(int userId) {
         if (userId == mCurrentUserId) return true;
         for (int i = 0; i < mCurrentProfileIds.length; i++) {
             if (mCurrentProfileIds[i] == userId) return true;
@@ -4340,7 +4339,7 @@
         final DisplayContent topFocusedDisplay = mRoot.getTopFocusedDisplayContent();
         final ActivityRecord focusedApp = topFocusedDisplay.mFocusedApp;
         return (focusedApp != null && focusedApp.getTask() != null)
-                ? focusedApp.getTask().getTaskStack() : null;
+                ? focusedApp.getTask().getStack() : null;
     }
 
     public boolean detectSafeMode() {
@@ -7659,7 +7658,7 @@
             return;
         }
 
-        final ActivityStack stack = task.getTaskStack();
+        final ActivityStack stack = task.getStack();
         // We ignore home stack since we don't want home stack to move to front when touched.
         // Specifically, in freeform we don't want tapping on home to cause the freeform apps to go
         // behind home. See b/117376413
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index bb7c26c..2ac1f39 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -56,19 +56,35 @@
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
+import static android.view.WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_PHONE;
+import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
+import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION;
+import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
+import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
+import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED;
@@ -523,9 +539,6 @@
 
     boolean mHasSurface = false;
 
-    /** When true this window can be displayed on screens owther than mOwnerUid's */
-    private boolean mShowToOwnerOnly;
-
     // This window will be replaced due to relaunch. This allows window manager
     // to differentiate between simple removal of a window and replacement. In the latter case it
     // will preserve the old window until the new one is drawn.
@@ -1287,7 +1300,7 @@
         // notify the client of frame changes in this case. Not only is it a lot of churn, but
         // the frame may not correspond to the surface size or the onscreen area at various
         // phases in the animation, and the client will become sad and confused.
-        if (task != null && task.getTaskStack().isAnimatingBounds()) {
+        if (task != null && task.getStack().isAnimatingBounds()) {
             return;
         }
 
@@ -1427,8 +1440,8 @@
     ActivityStack getStack() {
         Task task = getTask();
         if (task != null) {
-            if (task.getTaskStack() != null) {
-                return task.getTaskStack();
+            if (task.getStack() != null) {
+                return task.getStack();
             }
         }
         // Some system windows (e.g. "Power off" dialog) don't have a task, but we would still
@@ -1447,7 +1460,7 @@
         bounds.setEmpty();
         mTmpRect.setEmpty();
         if (intersectWithStackBounds) {
-            final ActivityStack stack = task.getTaskStack();
+            final ActivityStack stack = task.getStack();
             if (stack != null) {
                 stack.getDimBounds(mTmpRect);
             } else {
@@ -1879,8 +1892,8 @@
         final int top = mWindowFrames.mFrame.top;
         final Task task = getTask();
         final boolean adjustedForMinimizedDockOrIme = task != null
-                && (task.getTaskStack().isAdjustedForMinimizedDockedStack()
-                || task.getTaskStack().isAdjustedForIme());
+                && (task.getStack().isAdjustedForMinimizedDockedStack()
+                || task.getStack().isAdjustedForIme());
         if (mToken.okToAnimate()
                 && (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
                 && !isDragResizing() && !adjustedForMinimizedDockOrIme
@@ -1916,7 +1929,7 @@
 
     boolean isObscuringDisplay() {
         Task task = getTask();
-        if (task != null && task.getTaskStack() != null && !task.getTaskStack().fillsParent()) {
+        if (task != null && task.getStack() != null && !task.getStack().fillsParent()) {
             return false;
         }
         return isOpaqueDrawn() && fillsDisplay();
@@ -2349,20 +2362,21 @@
 
     void applyAdjustForImeIfNeeded() {
         final Task task = getTask();
-        if (task != null && task.getTaskStack() != null && task.getTaskStack().isAdjustedForIme()) {
-            task.getTaskStack().applyAdjustForImeIfNeeded(task);
+        if (task != null && task.getStack() != null && task.getStack().isAdjustedForIme()) {
+            task.getStack().applyAdjustForImeIfNeeded(task);
         }
     }
 
     @Override
     void switchUser(int userId) {
         super.switchUser(userId);
-        if (isHiddenFromUserLocked()) {
+
+        if (showToCurrentUser()) {
+            setPolicyVisibilityFlag(VISIBLE_FOR_USER);
+        } else {
             if (DEBUG_VISIBILITY) Slog.w(TAG_WM, "user changing, hiding " + this
                     + ", attrs=" + mAttrs.type + ", belonging to " + mOwnerUid);
             clearPolicyVisibilityFlag(VISIBLE_FOR_USER);
-        } else {
-            setPolicyVisibilityFlag(VISIBLE_FOR_USER);
         }
     }
 
@@ -2694,7 +2708,7 @@
             return false;
         }
 
-        return mActivityRecord.getTask().getTaskStack().shouldIgnoreInput()
+        return mActivityRecord.getTask().getStack().shouldIgnoreInput()
                 || !mActivityRecord.mVisibleRequested
                 || isRecentsAnimationConsumingAppInput();
     }
@@ -2725,7 +2739,7 @@
             // Already showing.
             return false;
         }
-        if (isHiddenFromUserLocked()) {
+        if (!showToCurrentUser()) {
             return false;
         }
         if (!mAppOpVisibility) {
@@ -3133,11 +3147,55 @@
         return displayContent.isDefaultDisplay;
     }
 
-    void setShowToOwnerOnlyLocked(boolean showToOwnerOnly) {
-        mShowToOwnerOnly = showToOwnerOnly;
+    /** @return {@code true} if this window can be shown to all users. */
+    boolean showForAllUsers() {
+
+        // If this switch statement is modified, modify the comment in the declarations of
+        // the type in {@link WindowManager.LayoutParams} as well.
+        switch (mAttrs.type) {
+            default:
+                // These are the windows that by default are shown only to the user that created
+                // them. If this needs to be overridden, set
+                // {@link WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS} in
+                // {@link WindowManager.LayoutParams}. Note that permission
+                // {@link android.Manifest.permission.INTERNAL_SYSTEM_WINDOW} is required as well.
+                if ((mAttrs.privateFlags & SYSTEM_FLAG_SHOW_FOR_ALL_USERS) == 0) {
+                    return false;
+                }
+                break;
+
+            // These are the windows that by default are shown to all users. However, to
+            // protect against spoofing, check permissions below.
+            case TYPE_APPLICATION_STARTING:
+            case TYPE_BOOT_PROGRESS:
+            case TYPE_DISPLAY_OVERLAY:
+            case TYPE_INPUT_CONSUMER:
+            case TYPE_KEYGUARD_DIALOG:
+            case TYPE_MAGNIFICATION_OVERLAY:
+            case TYPE_NAVIGATION_BAR:
+            case TYPE_NAVIGATION_BAR_PANEL:
+            case TYPE_PHONE:
+            case TYPE_POINTER:
+            case TYPE_PRIORITY_PHONE:
+            case TYPE_SEARCH_BAR:
+            case TYPE_STATUS_BAR:
+            case TYPE_STATUS_BAR_PANEL:
+            case TYPE_STATUS_BAR_SUB_PANEL:
+            case TYPE_SYSTEM_DIALOG:
+            case TYPE_VOLUME_OVERLAY:
+            case TYPE_PRESENTATION:
+            case TYPE_PRIVATE_PRESENTATION:
+            case TYPE_DOCK_DIVIDER:
+                break;
+        }
+
+        // Only the system can show free windows to all users.
+        return mOwnerCanAddInternalSystemWindow;
+
     }
 
-    private boolean isHiddenFromUserLocked() {
+    @Override
+    boolean showToCurrentUser() {
         // Child windows are evaluated based on their parent window.
         final WindowState win = getTopParentWindow();
         if (win.mAttrs.type < FIRST_SYSTEM_WINDOW
@@ -3151,12 +3209,12 @@
                     && win.getFrameLw().right >= win.getStableFrameLw().right
                     && win.getFrameLw().bottom >= win.getStableFrameLw().bottom) {
                 // Is a fullscreen window, like the clock alarm. Show to everyone.
-                return false;
+                return true;
             }
         }
 
-        return win.mShowToOwnerOnly
-                && !mWmService.isCurrentProfileLocked(UserHandle.getUserId(win.mOwnerUid));
+        return win.showForAllUsers()
+                || mWmService.isCurrentProfile(UserHandle.getUserId(win.mOwnerUid));
     }
 
     private static void applyInsets(Region outRegion, Rect frame, Rect inset) {
@@ -3214,7 +3272,7 @@
             return;
         }
 
-        final ActivityStack stack = task.getTaskStack();
+        final ActivityStack stack = task.getStack();
         if (stack == null) {
             return;
         }
@@ -3228,7 +3286,7 @@
             return;
         }
 
-        final ActivityStack stack = task.getTaskStack();
+        final ActivityStack stack = task.getStack();
         if (stack == null) {
             return;
         }
@@ -3716,7 +3774,7 @@
         pw.println(" mSession=" + mSession
                 + " mClient=" + mClient.asBinder());
         pw.println(prefix + "mOwnerUid=" + mOwnerUid
-                + " mShowToOwnerOnly=" + mShowToOwnerOnly
+                + " showForAllUsers=" + showForAllUsers()
                 + " package=" + mAttrs.packageName
                 + " appop=" + AppOpsManager.opToName(mAppOp));
         pw.println(prefix + "mAttrs=" + mAttrs.toString(prefix));
@@ -4160,7 +4218,7 @@
 
     // This must be called while inside a transaction.
     boolean performShowLocked() {
-        if (isHiddenFromUserLocked()) {
+        if (!showToCurrentUser()) {
             if (DEBUG_VISIBILITY) Slog.w(TAG, "hiding " + this + ", belonging to " + mOwnerUid);
             clearPolicyVisibilityFlag(VISIBLE_FOR_USER);
             return false;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 175fccb..1a11766 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -888,10 +888,10 @@
 
             int posX = 0;
             int posY = 0;
-            task.getTaskStack().getDimBounds(mTmpStackBounds);
+            task.getStack().getDimBounds(mTmpStackBounds);
 
             boolean allowStretching = false;
-            task.getTaskStack().getFinalAnimationSourceHintBounds(mTmpSourceBounds);
+            task.getStack().getFinalAnimationSourceHintBounds(mTmpSourceBounds);
             // If we don't have source bounds, we can attempt to use the content insets
             // in the following scenario:
             //    1. We have content insets.
@@ -901,8 +901,8 @@
             // because of the force-scale until resize state.
             if (mTmpSourceBounds.isEmpty() && (mWin.mLastRelayoutContentInsets.width() > 0
                     || mWin.mLastRelayoutContentInsets.height() > 0)
-                        && !task.getTaskStack().lastAnimatingBoundsWasToFullscreen()) {
-                mTmpSourceBounds.set(task.getTaskStack().mPreAnimationBounds);
+                        && !task.getStack().lastAnimatingBoundsWasToFullscreen()) {
+                mTmpSourceBounds.set(task.getStack().mPreAnimationBounds);
                 mTmpSourceBounds.inset(mWin.mLastRelayoutContentInsets);
                 allowStretching = true;
             }
@@ -916,7 +916,7 @@
             if (!mTmpSourceBounds.isEmpty()) {
                 // Get the final target stack bounds, if we are not animating, this is just the
                 // current stack bounds
-                task.getTaskStack().getFinalAnimationBounds(mTmpAnimatingBounds);
+                task.getStack().getFinalAnimationBounds(mTmpAnimatingBounds);
 
                 // Calculate the current progress and interpolate the difference between the target
                 // and source bounds
@@ -1495,7 +1495,7 @@
      */
     boolean isForceScaled() {
         final Task task = mWin.getTask();
-        if (task != null && task.getTaskStack().isForceScaled()) {
+        if (task != null && task.getStack().isForceScaled()) {
             return true;
         }
         return mForceScaleUntilResize;
diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
index 4d4a7b4..4696dd0 100644
--- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp
+++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
@@ -54,7 +54,7 @@
     TCP_TX_PACKETS = 5
 };
 
-static uint64_t getStatsType(struct Stats* stats, StatsType type) {
+static uint64_t getStatsType(Stats* stats, StatsType type) {
     switch (type) {
         case RX_BYTES:
             return stats->rxBytes;
@@ -73,7 +73,7 @@
     }
 }
 
-static int parseIfaceStats(const char* iface, struct Stats* stats) {
+static int parseIfaceStats(const char* iface, Stats* stats) {
     FILE *fp = fopen(QTAGUID_IFACE_STATS, "r");
     if (fp == NULL) {
         return -1;
@@ -117,7 +117,7 @@
     return 0;
 }
 
-static int parseUidStats(const uint32_t uid, struct Stats* stats) {
+static int parseUidStats(const uint32_t uid, Stats* stats) {
     FILE *fp = fopen(QTAGUID_UID_STATS, "r");
     if (fp == NULL) {
         return -1;
@@ -150,8 +150,7 @@
 }
 
 static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type, jboolean useBpfStats) {
-    struct Stats stats;
-    memset(&stats, 0, sizeof(Stats));
+    Stats stats = {};
 
     if (useBpfStats) {
         if (bpfGetIfaceStats(NULL, &stats) == 0) {
@@ -175,8 +174,7 @@
         return UNKNOWN;
     }
 
-    struct Stats stats;
-    memset(&stats, 0, sizeof(Stats));
+    Stats stats = {};
 
     if (useBpfStats) {
         if (bpfGetIfaceStats(iface8.c_str(), &stats) == 0) {
@@ -194,8 +192,7 @@
 }
 
 static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type, jboolean useBpfStats) {
-    struct Stats stats;
-    memset(&stats, 0, sizeof(Stats));
+    Stats stats = {};
 
     if (useBpfStats) {
         if (bpfGetUidStats(uid, &stats) == 0) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1536816..c275ccc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -215,6 +215,7 @@
 import android.provider.ContactsInternal;
 import android.provider.Settings;
 import android.provider.Settings.Global;
+import android.provider.Telephony;
 import android.security.IKeyChainAliasCallback;
 import android.security.IKeyChainService;
 import android.security.KeyChain;
@@ -303,6 +304,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -2266,23 +2268,23 @@
     @VisibleForTesting
     DevicePolicyManagerService(Injector injector) {
         mInjector = injector;
-        mContext = Preconditions.checkNotNull(injector.mContext);
-        mHandler = new Handler(Preconditions.checkNotNull(injector.getMyLooper()));
+        mContext = Objects.requireNonNull(injector.mContext);
+        mHandler = new Handler(Objects.requireNonNull(injector.getMyLooper()));
 
         mConstantsObserver = new DevicePolicyConstantsObserver(mHandler);
         mConstantsObserver.register();
         mConstants = loadConstants();
 
-        mOwners = Preconditions.checkNotNull(injector.newOwners());
+        mOwners = Objects.requireNonNull(injector.newOwners());
 
-        mUserManager = Preconditions.checkNotNull(injector.getUserManager());
-        mUserManagerInternal = Preconditions.checkNotNull(injector.getUserManagerInternal());
-        mUsageStatsManagerInternal = Preconditions.checkNotNull(
+        mUserManager = Objects.requireNonNull(injector.getUserManager());
+        mUserManagerInternal = Objects.requireNonNull(injector.getUserManagerInternal());
+        mUsageStatsManagerInternal = Objects.requireNonNull(
                 injector.getUsageStatsManagerInternal());
-        mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager());
-        mIPlatformCompat = Preconditions.checkNotNull(injector.getIPlatformCompat());
-        mIPermissionManager = Preconditions.checkNotNull(injector.getIPermissionManager());
-        mTelephonyManager = Preconditions.checkNotNull(injector.getTelephonyManager());
+        mIPackageManager = Objects.requireNonNull(injector.getIPackageManager());
+        mIPlatformCompat = Objects.requireNonNull(injector.getIPlatformCompat());
+        mIPermissionManager = Objects.requireNonNull(injector.getIPermissionManager());
+        mTelephonyManager = Objects.requireNonNull(injector.getTelephonyManager());
 
         mLocalService = new LocalService();
         mLockPatternUtils = injector.newLockPatternUtils();
@@ -4047,7 +4049,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(adminReceiver, "ComponentName is null");
+        Objects.requireNonNull(adminReceiver, "ComponentName is null");
         enforceShell("forceRemoveActiveAdmin");
         mInjector.binderWithCleanCallingIdentity(() -> {
             synchronized (getLockObject()) {
@@ -4164,7 +4166,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         validateQualityConstant(quality);
 
         final int userId = mInjector.userHandleGetCallingUserId();
@@ -4377,7 +4379,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userId = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
             ActiveAdmin ap = getActiveAdminForCallerLocked(
@@ -4419,7 +4421,7 @@
         if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userId = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
             ActiveAdmin ap = getActiveAdminForCallerLocked(
@@ -4451,7 +4453,7 @@
         if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         Preconditions.checkArgumentNonnegative(timeout, "Timeout must be >= 0 ms");
         final int userHandle = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
@@ -4633,7 +4635,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userId = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
             final ActiveAdmin ap = getActiveAdminForCallerLocked(
@@ -4663,7 +4665,7 @@
 
     @Override
     public void setPasswordMinimumLowerCase(ComponentName who, int length, boolean parent) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userId = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
             ActiveAdmin ap = getActiveAdminForCallerLocked(
@@ -4696,7 +4698,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userId = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
             ActiveAdmin ap = getActiveAdminForCallerLocked(
@@ -4728,7 +4730,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userId = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
             ActiveAdmin ap = getActiveAdminForCallerLocked(
@@ -4760,7 +4762,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userId = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
             ActiveAdmin ap = getActiveAdminForCallerLocked(
@@ -4792,7 +4794,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userId = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
             ActiveAdmin ap = getActiveAdminForCallerLocked(
@@ -5019,7 +5021,7 @@
         if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userId = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
             // This API can only be called by an active device admin,
@@ -5259,7 +5261,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userHandle = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
             final ActiveAdmin ap = getActiveAdminForCallerLocked(
@@ -5360,7 +5362,7 @@
         if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         Preconditions.checkArgument(timeoutMs >= 0, "Timeout must not be a negative number.");
         // timeoutMs with value 0 means that the admin doesn't participate
         // timeoutMs is clamped to the interval in case the internal constants change in the future
@@ -6108,7 +6110,7 @@
     @Override
     public void setDelegatedScopes(ComponentName who, String delegatePackage,
             List<String> scopeList) throws SecurityException {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         Preconditions.checkStringNotEmpty(delegatePackage, "Delegate package is null or empty");
         Preconditions.checkCollectionElementsNotNull(scopeList, "Scopes");
         // Remove possible duplicates.
@@ -6206,7 +6208,7 @@
     @NonNull
     public List<String> getDelegatedScopes(ComponentName who,
             String delegatePackage) throws SecurityException {
-        Preconditions.checkNotNull(delegatePackage, "Delegate package is null");
+        Objects.requireNonNull(delegatePackage, "Delegate package is null");
 
         // Retrieve the user ID of the calling process.
         final int callingUid = mInjector.binderGetCallingUid();
@@ -6246,8 +6248,8 @@
     @NonNull
     public List<String> getDelegatePackages(ComponentName who, String scope)
             throws SecurityException {
-        Preconditions.checkNotNull(who, "ComponentName is null");
-        Preconditions.checkNotNull(scope, "Scope is null");
+        Objects.requireNonNull(who, "ComponentName is null");
+        Objects.requireNonNull(scope, "Scope is null");
         if (!Arrays.asList(DELEGATIONS).contains(scope)) {
             throw new IllegalArgumentException("Unexpected delegation scope: " + scope);
         }
@@ -6329,7 +6331,7 @@
      * @return {@code true} if the calling process is a delegate of {@code scope}.
      */
     private boolean isCallerDelegate(String callerPackage, int callerUid, String scope) {
-        Preconditions.checkNotNull(callerPackage, "callerPackage is null");
+        Objects.requireNonNull(callerPackage, "callerPackage is null");
         if (!Arrays.asList(DELEGATIONS).contains(scope)) {
             throw new IllegalArgumentException("Unexpected delegation scope: " + scope);
         }
@@ -6410,7 +6412,7 @@
      */
     private void setDelegatedScopePreO(ComponentName who,
             String delegatePackage, String scope) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
 
         final int userId = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
@@ -6938,7 +6940,7 @@
             return null;
         }
         synchronized (getLockObject()) {
-            Preconditions.checkNotNull(who, "ComponentName is null");
+            Objects.requireNonNull(who, "ComponentName is null");
 
             // Only check if system user has set global proxy. We don't allow other users to set it.
             DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
@@ -7066,7 +7068,7 @@
         if (!mHasFeature) {
             return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (getLockObject()) {
             // Check for permissions
@@ -7220,7 +7222,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (getLockObject()) {
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
@@ -7287,7 +7289,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (getLockObject()) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
@@ -7347,7 +7349,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         // TODO (b/145286957) Refactor security checks
         enforceDeviceOwnerOrProfileOwnerOnUser0OrProfileOwnerOrganizationOwned();
 
@@ -7369,7 +7371,7 @@
         if (!mHasFeature) {
             return false;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         enforceDeviceOwnerOrProfileOwnerOnUser0OrProfileOwnerOrganizationOwned();
 
         return mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) > 0;
@@ -7383,7 +7385,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         // TODO (b/145286957) Refactor security checks
         enforceDeviceOwnerOrProfileOwnerOnUser0OrProfileOwnerOrganizationOwned();
 
@@ -7405,7 +7407,7 @@
         if (!mHasFeature) {
             return false;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         enforceDeviceOwnerOrProfileOwnerOnUser0OrProfileOwnerOrganizationOwned();
 
         return mInjector.settingsGlobalGetInt(Global.AUTO_TIME_ZONE, 0) > 0;
@@ -7416,7 +7418,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         // Allow setting this policy to true only if there is a split system user.
         if (forceEphemeralUsers && !mInjector.userManagerIsSplitSystemUser()) {
             throw new UnsupportedOperationException(
@@ -7443,7 +7445,7 @@
         if (!mHasFeature) {
             return false;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         synchronized (getLockObject()) {
             final ActiveAdmin deviceOwner =
                     getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
@@ -7472,7 +7474,7 @@
         if (!mHasFeature) {
             return false;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
 
         // TODO: If an unaffiliated user is removed, the admin will be able to request a bugreport
         // which could still contain data related to that user. Should we disallow that, e.g. until
@@ -7709,7 +7711,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         int userHandle = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
@@ -7779,7 +7781,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userHandle = mInjector.userHandleGetCallingUserId();
         if (isManagedProfile(userHandle)) {
             if (parent) {
@@ -7867,7 +7869,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(packageList, "packageList is null");
+        Objects.requireNonNull(packageList, "packageList is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (getLockObject()) {
             // Ensure the caller is a DO or a keep uninstalled packages delegate.
@@ -8104,7 +8106,7 @@
 
     @Override
     public void clearDeviceOwner(String packageName) {
-        Preconditions.checkNotNull(packageName, "packageName is null");
+        Objects.requireNonNull(packageName, "packageName is null");
         final int callingUid = mInjector.binderGetCallingUid();
         try {
             int uid = mInjector.getPackageManager().getPackageUidAsUser(packageName,
@@ -8259,7 +8261,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
 
         final int userId = mInjector.userHandleGetCallingUserId();
         enforceNotManagedProfile(userId, "clear profile owner");
@@ -8300,7 +8302,7 @@
 
     @Override
     public void setDeviceOwnerLockScreenInfo(ComponentName who, CharSequence info) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         if (!mHasFeature) {
             return;
         }
@@ -8470,7 +8472,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         synchronized (getLockObject()) {
             // Check if this is the profile owner who is calling
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -8497,7 +8499,7 @@
 
     @Override
     public void setProfileName(ComponentName who, String profileName) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         enforceProfileOrDeviceOwner(who);
 
         final int userId = UserHandle.getCallingUserId();
@@ -9090,7 +9092,7 @@
     @Override
     public void addPersistentPreferredActivity(ComponentName who, IntentFilter filter,
             ComponentName activity) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (getLockObject()) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -9116,7 +9118,7 @@
 
     @Override
     public void clearPackagePersistentPreferredActivities(ComponentName who, String packageName) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (getLockObject()) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -9135,7 +9137,7 @@
 
     @Override
     public void setDefaultSmsApplication(ComponentName admin, String packageName) {
-        Preconditions.checkNotNull(admin, "ComponentName is null");
+        Objects.requireNonNull(admin, "ComponentName is null");
         enforceDeviceOwner(admin);
         mInjector.binderWithCleanCallingIdentity(() ->
                 SmsApplication.setDefaultApplication(packageName, mContext));
@@ -9190,8 +9192,8 @@
         if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return;
         }
-        Preconditions.checkNotNull(admin, "admin is null");
-        Preconditions.checkNotNull(agent, "agent is null");
+        Objects.requireNonNull(admin, "admin is null");
+        Objects.requireNonNull(agent, "agent is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (getLockObject()) {
             ActiveAdmin ap = getActiveAdminForCallerLocked(admin,
@@ -9207,7 +9209,7 @@
         if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return null;
         }
-        Preconditions.checkNotNull(agent, "agent null");
+        Objects.requireNonNull(agent, "agent null");
         enforceFullCrossUsersPermission(userHandle);
 
         synchronized (getLockObject()) {
@@ -9259,7 +9261,7 @@
 
     @Override
     public void setRestrictionsProvider(ComponentName who, ComponentName permissionProvider) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         synchronized (getLockObject()) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
@@ -9281,7 +9283,7 @@
 
     @Override
     public void addCrossProfileIntentFilter(ComponentName who, IntentFilter filter, int flags) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         int callingUserId = UserHandle.getCallingUserId();
         synchronized (getLockObject()) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -9330,7 +9332,7 @@
 
     @Override
     public void clearCrossProfileIntentFilters(ComponentName who) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         int callingUserId = UserHandle.getCallingUserId();
         synchronized (getLockObject()) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -9407,7 +9409,7 @@
         if (!mHasFeature) {
             return false;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
 
         if (packageList != null) {
             int userId = UserHandle.getCallingUserId();
@@ -9460,7 +9462,7 @@
         if (!mHasFeature) {
             return null;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
 
         synchronized (getLockObject()) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
@@ -9536,7 +9538,7 @@
         if (!mHasFeature) {
             return true;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         Preconditions.checkStringNotEmpty(packageName, "packageName is null");
         enforceSystemCaller("query if an accessibility service is disabled by admin");
 
@@ -9587,7 +9589,7 @@
         if (!mHasFeature) {
             return false;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int callingUserId = mInjector.userHandleGetCallingUserId();
         if (packageList != null) {
             List<InputMethodInfo> enabledImes = InputMethodManagerInternal.get()
@@ -9627,7 +9629,7 @@
         if (!mHasFeature) {
             return null;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
 
         synchronized (getLockObject()) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
@@ -9681,7 +9683,7 @@
         if (!mHasFeature) {
             return true;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         Preconditions.checkStringNotEmpty(packageName, "packageName is null");
         enforceSystemCaller("query if an input method is disabled by admin");
 
@@ -9704,7 +9706,7 @@
         if (!mHasFeature) {
             return false;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
 
         final int callingUserId = mInjector.userHandleGetCallingUserId();
         if (!isManagedProfile(callingUserId)) {
@@ -9725,7 +9727,7 @@
         if (!mHasFeature) {
             return null;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
 
         synchronized (getLockObject()) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(
@@ -9787,8 +9789,8 @@
     @Override
     public UserHandle createAndManageUser(ComponentName admin, String name,
             ComponentName profileOwner, PersistableBundle adminExtras, int flags) {
-        Preconditions.checkNotNull(admin, "admin is null");
-        Preconditions.checkNotNull(profileOwner, "profileOwner is null");
+        Objects.requireNonNull(admin, "admin is null");
+        Objects.requireNonNull(profileOwner, "profileOwner is null");
         if (!admin.getPackageName().equals(profileOwner.getPackageName())) {
             throw new IllegalArgumentException("profileOwner " + profileOwner + " and admin "
                     + admin + " are not in the same package");
@@ -9919,8 +9921,8 @@
 
     @Override
     public boolean removeUser(ComponentName who, UserHandle userHandle) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
-        Preconditions.checkNotNull(userHandle, "UserHandle is null");
+        Objects.requireNonNull(who, "ComponentName is null");
+        Objects.requireNonNull(userHandle, "UserHandle is null");
         enforceDeviceOwner(who);
 
         final int callingUserId = mInjector.userHandleGetCallingUserId();
@@ -9953,7 +9955,7 @@
 
     @Override
     public boolean switchUser(ComponentName who, UserHandle userHandle) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
 
         synchronized (getLockObject()) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
@@ -9976,8 +9978,8 @@
 
     @Override
     public int startUserInBackground(ComponentName who, UserHandle userHandle) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
-        Preconditions.checkNotNull(userHandle, "UserHandle is null");
+        Objects.requireNonNull(who, "ComponentName is null");
+        Objects.requireNonNull(userHandle, "UserHandle is null");
         enforceDeviceOwner(who);
 
         final int userId = userHandle.getIdentifier();
@@ -10008,8 +10010,8 @@
 
     @Override
     public int stopUser(ComponentName who, UserHandle userHandle) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
-        Preconditions.checkNotNull(userHandle, "UserHandle is null");
+        Objects.requireNonNull(who, "ComponentName is null");
+        Objects.requireNonNull(userHandle, "UserHandle is null");
         enforceDeviceOwner(who);
 
         final int userId = userHandle.getIdentifier();
@@ -10023,7 +10025,7 @@
 
     @Override
     public int logoutUser(ComponentName who) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
 
         final int callingUserId = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
@@ -10077,7 +10079,7 @@
 
     @Override
     public List<UserHandle> getSecondaryUsers(ComponentName who) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         enforceDeviceOwner(who);
 
         return mInjector.binderWithCleanCallingIdentity(() -> {
@@ -10096,7 +10098,7 @@
 
     @Override
     public boolean isEphemeralUser(ComponentName who) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         enforceProfileOrDeviceOwner(who);
 
         final int callingUserId = mInjector.userHandleGetCallingUserId();
@@ -10178,7 +10180,7 @@
     @Override
     public void setUserRestriction(ComponentName who, String key, boolean enabledFromThisOwner,
             boolean parent) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         if (!UserRestrictionsUtils.isValidRestriction(key)) {
             return;
         }
@@ -10324,7 +10326,7 @@
         if (!mHasFeature) {
             return null;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
 
         synchronized (getLockObject()) {
             final ActiveAdmin activeAdmin = getActiveAdminForCallerLocked(who,
@@ -10559,7 +10561,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         synchronized (getLockObject()) {
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -10653,7 +10655,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         synchronized (getLockObject()) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -10674,7 +10676,7 @@
         if (!mHasFeature) {
             return false;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         synchronized (getLockObject()) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -10696,7 +10698,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         synchronized (getLockObject()) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -10717,7 +10719,7 @@
         if (!mHasFeature) {
             return false;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         synchronized (getLockObject()) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -10797,7 +10799,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         synchronized (getLockObject()) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -10818,7 +10820,7 @@
         if (!mHasFeature) {
             return false;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         synchronized (getLockObject()) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -10840,8 +10842,8 @@
     @Override
     public void setLockTaskPackages(ComponentName who, String[] packages)
             throws SecurityException {
-        Preconditions.checkNotNull(who, "ComponentName is null");
-        Preconditions.checkNotNull(packages, "packages is null");
+        Objects.requireNonNull(who, "ComponentName is null");
+        Objects.requireNonNull(packages, "packages is null");
 
         synchronized (getLockObject()) {
             enforceCanCallLockTaskLocked(who);
@@ -10861,7 +10863,7 @@
 
     @Override
     public String[] getLockTaskPackages(ComponentName who) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
 
         final int userHandle = mInjector.binderGetCallingUserHandle().getIdentifier();
         synchronized (getLockObject()) {
@@ -10881,7 +10883,7 @@
 
     @Override
     public void setLockTaskFeatures(ComponentName who, int flags) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
 
         // Throw if Overview is used without Home.
         boolean hasHome = (flags & LOCK_TASK_FEATURE_HOME) != 0;
@@ -10908,7 +10910,7 @@
 
     @Override
     public int getLockTaskFeatures(ComponentName who) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userHandle = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
             enforceCanCallLockTaskLocked(who);
@@ -10978,7 +10980,7 @@
 
     @Override
     public void setGlobalSetting(ComponentName who, String setting, String value) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
 
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_GLOBAL_SETTING)
@@ -11018,7 +11020,7 @@
 
     @Override
     public void setSystemSetting(ComponentName who, String setting, String value) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         Preconditions.checkStringNotEmpty(setting, "String setting is null or empty");
 
         synchronized (getLockObject()) {
@@ -11038,7 +11040,7 @@
 
     @Override
     public void setLocationEnabled(ComponentName who, boolean locationEnabled) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         enforceDeviceOwner(who);
 
         UserHandle userHandle = mInjector.binderGetCallingUserHandle();
@@ -11057,8 +11059,8 @@
 
     @Override
     public boolean setTime(ComponentName who, long millis) {
-        Preconditions.checkNotNull(who, "ComponentName is null in setTime");
-        enforceDeviceOwner(who);
+        Objects.requireNonNull(who, "ComponentName is null in setTime");
+        enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(who);
         // Don't allow set time when auto time is on.
         if (mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) == 1) {
             return false;
@@ -11072,8 +11074,8 @@
 
     @Override
     public boolean setTimeZone(ComponentName who, String timeZone) {
-        Preconditions.checkNotNull(who, "ComponentName is null in setTimeZone");
-        enforceDeviceOwner(who);
+        Objects.requireNonNull(who, "ComponentName is null in setTimeZone");
+        enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(who);
         // Don't allow set timezone when auto timezone is on.
         if (mInjector.settingsGlobalGetInt(Global.AUTO_TIME_ZONE, 0) == 1) {
             return false;
@@ -11088,7 +11090,7 @@
 
     @Override
     public void setSecureSetting(ComponentName who, String setting, String value) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         int callingUserId = mInjector.userHandleGetCallingUserId();
 
         synchronized (getLockObject()) {
@@ -11159,7 +11161,7 @@
 
     @Override
     public void setMasterVolumeMuted(ComponentName who, boolean on) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         synchronized (getLockObject()) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             setUserRestriction(who, UserManager.DISALLOW_UNMUTE_DEVICE, on, /* parent */ false);
@@ -11173,7 +11175,7 @@
 
     @Override
     public boolean isMasterVolumeMuted(ComponentName who) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         synchronized (getLockObject()) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
@@ -11186,7 +11188,7 @@
     @Override
     public void setUserIcon(ComponentName who, Bitmap icon) {
         synchronized (getLockObject()) {
-            Preconditions.checkNotNull(who, "ComponentName is null");
+            Objects.requireNonNull(who, "ComponentName is null");
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             int userId = UserHandle.getCallingUserId();
@@ -11201,7 +11203,7 @@
 
     @Override
     public boolean setKeyguardDisabled(ComponentName who, boolean disabled) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userId = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -11664,7 +11666,7 @@
 
     @Override
     public Intent createAdminSupportIntent(String restriction) {
-        Preconditions.checkNotNull(restriction);
+        Objects.requireNonNull(restriction);
         final int uid = mInjector.binderGetCallingUid();
         final int userId = UserHandle.getUserId(uid);
         Intent intent = null;
@@ -11922,7 +11924,7 @@
 
     @Override
     public SystemUpdateInfo getPendingSystemUpdate(ComponentName admin) {
-        Preconditions.checkNotNull(admin, "ComponentName is null");
+        Objects.requireNonNull(admin, "ComponentName is null");
         enforceProfileOrDeviceOwner(admin);
 
         return mOwners.getSystemUpdateInfo();
@@ -11964,7 +11966,7 @@
     public void setPermissionGrantState(ComponentName admin, String callerPackage,
             String packageName, String permission, int grantState, RemoteCallback callback)
             throws RemoteException {
-        Preconditions.checkNotNull(callback);
+        Objects.requireNonNull(callback);
 
         UserHandle user = mInjector.binderGetCallingUserHandle();
         synchronized (getLockObject()) {
@@ -12099,7 +12101,7 @@
 
     @Override
     public boolean isProvisioningAllowed(String action, String packageName) {
-        Preconditions.checkNotNull(packageName);
+        Objects.requireNonNull(packageName);
 
         final int callingUid = mInjector.binderGetCallingUid();
         final long ident = mInjector.binderClearCallingIdentity();
@@ -12119,7 +12121,7 @@
 
     @Override
     public int checkProvisioningPreCondition(String action, String packageName) {
-        Preconditions.checkNotNull(packageName);
+        Objects.requireNonNull(packageName);
         enforceCanManageProfileAndDeviceOwners();
         return checkProvisioningPreConditionSkipPermission(action, packageName);
     }
@@ -12359,7 +12361,7 @@
 
     @Override
     public void reboot(ComponentName admin) {
-        Preconditions.checkNotNull(admin);
+        Objects.requireNonNull(admin);
         // Make sure caller has DO.
         enforceDeviceOwner(admin);
         mInjector.binderWithCleanCallingIdentity(() -> {
@@ -12380,7 +12382,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userHandle = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
             ActiveAdmin admin = getActiveAdminForUidLocked(who, mInjector.binderGetCallingUid());
@@ -12400,7 +12402,7 @@
         if (!mHasFeature) {
             return null;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         synchronized (getLockObject()) {
             ActiveAdmin admin = getActiveAdminForUidLocked(who, mInjector.binderGetCallingUid());
             return admin.shortSupportMessage;
@@ -12412,7 +12414,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userHandle = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
             ActiveAdmin admin = getActiveAdminForUidLocked(who, mInjector.binderGetCallingUid());
@@ -12432,7 +12434,7 @@
         if (!mHasFeature) {
             return null;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         synchronized (getLockObject()) {
             ActiveAdmin admin = getActiveAdminForUidLocked(who, mInjector.binderGetCallingUid());
             return admin.longSupportMessage;
@@ -12444,7 +12446,7 @@
         if (!mHasFeature) {
             return null;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         enforceSystemCaller("query support message for user");
 
         synchronized (getLockObject()) {
@@ -12461,7 +12463,7 @@
         if (!mHasFeature) {
             return null;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         enforceSystemCaller("query support message for user");
 
         synchronized (getLockObject()) {
@@ -12478,7 +12480,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userHandle = mInjector.userHandleGetCallingUserId();
         enforceManagedProfile(userHandle, "set organization color");
         synchronized (getLockObject()) {
@@ -12513,7 +12515,7 @@
         if (!mHasFeature) {
             return ActiveAdmin.DEF_ORGANIZATION_COLOR;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         enforceManagedProfile(mInjector.userHandleGetCallingUserId(), "get organization color");
         synchronized (getLockObject()) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
@@ -12542,7 +12544,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         final int userHandle = mInjector.userHandleGetCallingUserId();
 
         synchronized (getLockObject()) {
@@ -12561,7 +12563,7 @@
         if (!mHasFeature) {
             return null;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         enforceManagedProfile(mInjector.userHandleGetCallingUserId(), "get organization name");
         synchronized (getLockObject()) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
@@ -12599,8 +12601,8 @@
 
     @Override
     public List<String> setMeteredDataDisabledPackages(ComponentName who, List<String> packageNames) {
-        Preconditions.checkNotNull(who);
-        Preconditions.checkNotNull(packageNames);
+        Objects.requireNonNull(who);
+        Objects.requireNonNull(packageNames);
 
         if (!mHasFeature) {
             return packageNames;
@@ -12646,7 +12648,7 @@
 
     @Override
     public List<String> getMeteredDataDisabledPackages(ComponentName who) {
-        Preconditions.checkNotNull(who);
+        Objects.requireNonNull(who);
 
         if (!mHasFeature) {
             return new ArrayList<>();
@@ -12662,7 +12664,7 @@
     @Override
     public boolean isMeteredDataDisabledPackageForUser(ComponentName who,
             String packageName, int userId) {
-        Preconditions.checkNotNull(who);
+        Objects.requireNonNull(who);
 
         if (!mHasFeature) {
             return false;
@@ -12688,7 +12690,7 @@
     public void markProfileOwnerOnOrganizationOwnedDevice(ComponentName who, int userId) {
         // As the caller is the system, it must specify the component name of the profile owner
         // as a sanity / safety check.
-        Preconditions.checkNotNull(who);
+        Objects.requireNonNull(who);
 
         if (!mHasFeature) {
             return;
@@ -12808,7 +12810,7 @@
             return Collections.emptyList();
         }
 
-        Preconditions.checkNotNull(admin);
+        Objects.requireNonNull(admin);
         synchronized (getLockObject()) {
             getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             return new ArrayList<String>(
@@ -12877,7 +12879,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(admin);
+        Objects.requireNonNull(admin);
 
         synchronized (getLockObject()) {
             getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
@@ -12907,7 +12909,7 @@
 
         synchronized (getLockObject()) {
             if (!isCallerWithSystemUid()) {
-                Preconditions.checkNotNull(admin);
+                Objects.requireNonNull(admin);
                 getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
             }
             return mInjector.securityLogGetLoggingEnabledProperty();
@@ -12931,7 +12933,7 @@
             return null;
         }
 
-        Preconditions.checkNotNull(admin);
+        Objects.requireNonNull(admin);
         ensureDeviceOwnerAndAllUsersAffiliated(admin);
 
         DevicePolicyEventLogger
@@ -12961,7 +12963,7 @@
             return null;
         }
 
-        Preconditions.checkNotNull(admin);
+        Objects.requireNonNull(admin);
         ensureDeviceOwnerAndAllUsersAffiliated(admin);
 
         if (!mInjector.securityLogGetLoggingEnabledProperty()) {
@@ -13206,7 +13208,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(admin);
+        Objects.requireNonNull(admin);
         enforceProfileOrDeviceOwner(admin);
         int userId = mInjector.userHandleGetCallingUserId();
         toggleBackupServiceActive(userId, enabled);
@@ -13214,7 +13216,7 @@
 
     @Override
     public boolean isBackupServiceEnabled(ComponentName admin) {
-        Preconditions.checkNotNull(admin);
+        Objects.requireNonNull(admin);
         if (!mHasFeature) {
             return true;
         }
@@ -13239,14 +13241,14 @@
         if (!mHasFeature) {
             return false;
         }
-        Preconditions.checkNotNull(admin);
-        Preconditions.checkNotNull(caller);
-        Preconditions.checkNotNull(serviceIntent);
+        Objects.requireNonNull(admin);
+        Objects.requireNonNull(caller);
+        Objects.requireNonNull(serviceIntent);
         Preconditions.checkArgument(
                 serviceIntent.getComponent() != null || serviceIntent.getPackage() != null,
                 "Service intent must be explicit (with a package name or component): "
                         + serviceIntent);
-        Preconditions.checkNotNull(connection);
+        Objects.requireNonNull(connection);
         Preconditions.checkArgument(mInjector.userHandleGetCallingUserId() != targetUserId,
                 "target user id must be different from the calling user id");
 
@@ -13290,7 +13292,7 @@
         if (!mHasFeature) {
             return Collections.emptyList();
         }
-        Preconditions.checkNotNull(admin);
+        Objects.requireNonNull(admin);
 
         synchronized (getLockObject()) {
             getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -13755,7 +13757,7 @@
         if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
             return false;
         }
-        Preconditions.checkNotNull(token);
+        Objects.requireNonNull(token);
         synchronized (getLockObject()) {
             final int userHandle = mInjector.userHandleGetCallingUserId();
             getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -13791,9 +13793,9 @@
     @Override
     public void clearApplicationUserData(ComponentName admin, String packageName,
             IPackageDataObserver callback) {
-        Preconditions.checkNotNull(admin, "ComponentName is null");
-        Preconditions.checkNotNull(packageName, "packageName is null");
-        Preconditions.checkNotNull(callback, "callback is null");
+        Objects.requireNonNull(admin, "ComponentName is null");
+        Objects.requireNonNull(packageName, "packageName is null");
+        Objects.requireNonNull(callback, "callback is null");
         enforceProfileOrDeviceOwner(admin);
         final int userId = UserHandle.getCallingUserId();
 
@@ -13824,7 +13826,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(admin);
+        Objects.requireNonNull(admin);
 
         synchronized (getLockObject()) {
             ActiveAdmin deviceOwner =
@@ -13865,8 +13867,8 @@
             return;
         }
 
-        Preconditions.checkNotNull(admin, "Admin cannot be null.");
-        Preconditions.checkNotNull(target, "Target cannot be null.");
+        Objects.requireNonNull(admin, "Admin cannot be null.");
+        Objects.requireNonNull(target, "Target cannot be null.");
 
         enforceProfileOrDeviceOwner(admin);
 
@@ -14001,7 +14003,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(admin);
+        Objects.requireNonNull(admin);
 
         final String startUserSessionMessageString =
                 startUserSessionMessage != null ? startUserSessionMessage.toString() : null;
@@ -14026,7 +14028,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(admin);
+        Objects.requireNonNull(admin);
 
         final String endUserSessionMessageString =
                 endUserSessionMessage != null ? endUserSessionMessage.toString() : null;
@@ -14051,7 +14053,7 @@
         if (!mHasFeature) {
             return null;
         }
-        Preconditions.checkNotNull(admin);
+        Objects.requireNonNull(admin);
 
         synchronized (getLockObject()) {
             final ActiveAdmin deviceOwner =
@@ -14065,7 +14067,7 @@
         if (!mHasFeature) {
             return null;
         }
-        Preconditions.checkNotNull(admin);
+        Objects.requireNonNull(admin);
 
         synchronized (getLockObject()) {
             final ActiveAdmin deviceOwner =
@@ -14108,22 +14110,18 @@
         if (!mHasFeature || !mHasTelephonyFeature) {
             return -1;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null in addOverrideApn");
-        Preconditions.checkNotNull(apnSetting, "ApnSetting is null in addOverrideApn");
+        Objects.requireNonNull(who, "ComponentName is null in addOverrideApn");
+        Objects.requireNonNull(apnSetting, "ApnSetting is null in addOverrideApn");
         enforceDeviceOwner(who);
 
-        int operatedId = -1;
-        Uri resultUri = mInjector.binderWithCleanCallingIdentity(() ->
-                mContext.getContentResolver().insert(DPC_URI, apnSetting.toContentValues()));
-        if (resultUri != null) {
-            try {
-                operatedId = Integer.parseInt(resultUri.getLastPathSegment());
-            } catch (NumberFormatException e) {
-                Slog.e(LOG_TAG, "Failed to parse inserted override APN id.", e);
-            }
+        TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+        if (tm != null) {
+            return mInjector.binderWithCleanCallingIdentity(
+                    () -> tm.addDevicePolicyOverrideApn(mContext, apnSetting));
+        } else {
+            Log.w(LOG_TAG, "TelephonyManager is null when trying to add override apn");
+            return Telephony.Carriers.INVALID_APN_ID;
         }
-
-        return operatedId;
     }
 
     @Override
@@ -14132,17 +14130,21 @@
         if (!mHasFeature || !mHasTelephonyFeature) {
             return false;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null in updateOverrideApn");
-        Preconditions.checkNotNull(apnSetting, "ApnSetting is null in updateOverrideApn");
+        Objects.requireNonNull(who, "ComponentName is null in updateOverrideApn");
+        Objects.requireNonNull(apnSetting, "ApnSetting is null in updateOverrideApn");
         enforceDeviceOwner(who);
 
         if (apnId < 0) {
             return false;
         }
-        return mInjector.binderWithCleanCallingIdentity(() ->
-                mContext.getContentResolver().update(
-                        Uri.withAppendedPath(DPC_URI, Integer.toString(apnId)),
-                        apnSetting.toContentValues(), null, null) > 0);
+        TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+        if (tm != null) {
+            return mInjector.binderWithCleanCallingIdentity(
+                    () -> tm.modifyDevicePolicyOverrideApn(mContext, apnId, apnSetting));
+        } else {
+            Log.w(LOG_TAG, "TelephonyManager is null when trying to modify override apn");
+            return false;
+        }
     }
 
     @Override
@@ -14150,7 +14152,7 @@
         if (!mHasFeature || !mHasTelephonyFeature) {
             return false;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null in removeOverrideApn");
+        Objects.requireNonNull(who, "ComponentName is null in removeOverrideApn");
         enforceDeviceOwner(who);
 
         return removeOverrideApnUnchecked(apnId);
@@ -14171,30 +14173,20 @@
         if (!mHasFeature || !mHasTelephonyFeature) {
             return Collections.emptyList();
         }
-        Preconditions.checkNotNull(who, "ComponentName is null in getOverrideApns");
+        Objects.requireNonNull(who, "ComponentName is null in getOverrideApns");
         enforceDeviceOwner(who);
 
         return getOverrideApnsUnchecked();
     }
 
     private List<ApnSetting> getOverrideApnsUnchecked() {
-        final Cursor cursor = mInjector.binderWithCleanCallingIdentity(
-                () -> mContext.getContentResolver().query(DPC_URI, null, null, null, null));
-
-        if (cursor == null) {
-            return Collections.emptyList();
+        TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+        if (tm != null) {
+            return mInjector.binderWithCleanCallingIdentity(
+                    () -> tm.getDevicePolicyOverrideApns(mContext));
         }
-        try {
-            List<ApnSetting> apnList = new ArrayList<ApnSetting>();
-            cursor.moveToPosition(-1);
-            while (cursor.moveToNext()) {
-                ApnSetting apn = ApnSetting.makeApnSetting(cursor);
-                apnList.add(apn);
-            }
-            return apnList;
-        } finally {
-            cursor.close();
-        }
+        Log.w(LOG_TAG, "TelephonyManager is null when trying to get override apns");
+        return Collections.emptyList();
     }
 
     @Override
@@ -14202,7 +14194,7 @@
         if (!mHasFeature || !mHasTelephonyFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null in setOverrideApnEnabled");
+        Objects.requireNonNull(who, "ComponentName is null in setOverrideApnEnabled");
         enforceDeviceOwner(who);
 
         setOverrideApnsEnabledUnchecked(enabled);
@@ -14220,7 +14212,7 @@
         if (!mHasFeature || !mHasTelephonyFeature) {
             return false;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null in isOverrideApnEnabled");
+        Objects.requireNonNull(who, "ComponentName is null in isOverrideApnEnabled");
         enforceDeviceOwner(who);
 
         Cursor enforceCursor = mInjector.binderWithCleanCallingIdentity(
@@ -14304,7 +14296,7 @@
             return PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
         }
 
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         enforceDeviceOwner(who);
 
         final int returnCode;
@@ -14342,7 +14334,7 @@
             return PRIVATE_DNS_MODE_UNKNOWN;
         }
 
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         enforceDeviceOwner(who);
         String currentMode = mInjector.settingsGlobalGetString(PRIVATE_DNS_MODE);
         if (currentMode == null) {
@@ -14366,7 +14358,7 @@
             return null;
         }
 
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
         enforceDeviceOwner(who);
 
         return mInjector.settingsGlobalGetString(PRIVATE_DNS_SPECIFIER);
@@ -14404,7 +14396,7 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
 
         synchronized (getLockObject()) {
             final ActiveAdmin admin = getActiveAdminForCallerLocked(
@@ -14425,7 +14417,7 @@
         if (!mHasFeature) {
             return Collections.emptyList();
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
 
         synchronized (getLockObject()) {
             final ActiveAdmin admin = getActiveAdminForCallerLocked(
@@ -14479,8 +14471,8 @@
         if (!mHasFeature) {
             return;
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
-        Preconditions.checkNotNull(packageNames, "Package names is null");
+        Objects.requireNonNull(who, "ComponentName is null");
+        Objects.requireNonNull(packageNames, "Package names is null");
         synchronized (getLockObject()) {
             final ActiveAdmin admin =
                     getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -14494,7 +14486,7 @@
         if (!mHasFeature) {
             return Collections.emptyList();
         }
-        Preconditions.checkNotNull(who, "ComponentName is null");
+        Objects.requireNonNull(who, "ComponentName is null");
 
         synchronized (getLockObject()) {
             final ActiveAdmin admin = getActiveAdminForCallerLocked(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java
index dd3bfc3..4b66bea 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java
@@ -39,6 +39,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
+import java.util.Objects;
 
 /**
  * Handles reading and writing of the owner transfer metadata file.
@@ -185,8 +186,8 @@
                 @NonNull int userId, @NonNull String adminType) {
             this.sourceComponent = sourceComponent;
             this.targetComponent = targetComponent;
-            Preconditions.checkNotNull(sourceComponent);
-            Preconditions.checkNotNull(targetComponent);
+            Objects.requireNonNull(sourceComponent);
+            Objects.requireNonNull(targetComponent);
             Preconditions.checkStringNotEmpty(adminType);
             this.userId = userId;
             this.adminType = adminType;
@@ -199,7 +200,7 @@
         }
 
         private static ComponentName unflattenComponentUnchecked(String flatComponent) {
-            Preconditions.checkNotNull(flatComponent);
+            Objects.requireNonNull(flatComponent);
             return ComponentName.unflattenFromString(flatComponent);
         }
 
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 529339e..0504d14 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -48,6 +48,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.PackageManagerInternal;
+import android.content.pm.parsing.AndroidPackage;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Process;
@@ -68,6 +69,7 @@
 import org.mockito.quality.Strictness;
 
 import java.io.File;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -138,11 +140,15 @@
                 .spyStatic(Settings.Global.class)
                 .startMocking();
 
-        // Mock LocalServices.getService(PackageManagerInternal.class).getApplicationInfo dependency
+        // Mock LocalServices.getService(PackageManagerInternal.class).getPackage dependency
         // needed by AppOpsService
         PackageManagerInternal mockPackageManagerInternal = mock(PackageManagerInternal.class);
-        when(mockPackageManagerInternal.getApplicationInfo(eq(sMyPackageName), anyInt(), anyInt(),
-                anyInt())).thenReturn(sContext.getApplicationInfo());
+        AndroidPackage mockMyPkg = mock(AndroidPackage.class);
+        when(mockMyPkg.isPrivileged()).thenReturn(false);
+        when(mockMyPkg.getUid()).thenReturn(mMyUid);
+        when(mockMyPkg.getFeatures()).thenReturn(Collections.emptyList());
+
+        when(mockPackageManagerInternal.getPackage(sMyPackageName)).thenReturn(mockMyPkg);
         doReturn(mockPackageManagerInternal).when(
                 () -> LocalServices.getService(PackageManagerInternal.class));
 
@@ -162,12 +168,12 @@
         mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED);
 
         // Note an op that's allowed.
-        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null);
+        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null);
         List<PackageOps> loggedOps = getLoggedOps();
         assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
 
         // Note another op that's not allowed.
-        mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName, null);
+        mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName, null, false, null);
         loggedOps = getLoggedOps();
         assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
         assertContainsOp(loggedOps, OP_WRITE_SMS, -1, mTestStartMillis, MODE_ERRORED);
@@ -183,16 +189,16 @@
         // This op controls WIFI_SCAN
         mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ALLOWED);
 
-        assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName, null))
-                .isEqualTo(MODE_ALLOWED);
+        assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName, null, false,
+                null)).isEqualTo(MODE_ALLOWED);
 
         assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, -1,
                 MODE_ALLOWED /* default for WIFI_SCAN; this is not changed or used in this test */);
 
         // Now set COARSE_LOCATION to ERRORED -> this will make WIFI_SCAN disabled as well.
         mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ERRORED);
-        assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName, null))
-                .isEqualTo(MODE_ERRORED);
+        assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName, null, false,
+                null)).isEqualTo(MODE_ERRORED);
 
         assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, mTestStartMillis,
                 MODE_ALLOWED /* default for WIFI_SCAN; this is not changed or used in this test */);
@@ -203,8 +209,8 @@
     public void testStatePersistence() {
         mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
         mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED);
-        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null);
-        mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName, null);
+        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null);
+        mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName, null, false, null);
         mAppOpsService.writeState();
 
         // Create a new app ops service, and initialize its state from XML.
@@ -221,7 +227,7 @@
     @Test
     public void testShutdown() {
         mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
-        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null);
+        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null);
         mAppOpsService.shutdown();
 
         // Create a new app ops service, and initialize its state from XML.
@@ -236,7 +242,7 @@
     @Test
     public void testGetOpsForPackage() {
         mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
-        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null);
+        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null);
 
         // Query all ops
         List<PackageOps> loggedOps = mAppOpsService.getOpsForPackage(
@@ -265,7 +271,7 @@
     @Test
     public void testPackageRemoved() {
         mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
-        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null);
+        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null);
 
         List<PackageOps> loggedOps = getLoggedOps();
         assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
@@ -278,7 +284,7 @@
     @Test
     public void testPackageRemovedHistoricalOps() throws InterruptedException {
         mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
-        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null);
+        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null);
 
         AppOpsManager.HistoricalOps historicalOps = new AppOpsManager.HistoricalOps(0, 15000);
         historicalOps.increaseAccessCount(OP_READ_SMS, mMyUid, sMyPackageName,
@@ -317,7 +323,7 @@
     @Test
     public void testUidRemoved() {
         mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
-        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null);
+        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null);
 
         List<PackageOps> loggedOps = getLoggedOps();
         assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
@@ -340,13 +346,13 @@
 
         mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
                 ActivityManager.PROCESS_CAPABILITY_NONE);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
-                .isNotEqualTo(MODE_ALLOWED);
+        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+                false, null)).isNotEqualTo(MODE_ALLOWED);
 
         mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP,
                 ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
-                .isEqualTo(MODE_ALLOWED);
+        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+                false, null)).isEqualTo(MODE_ALLOWED);
 
         mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
                 ActivityManager.PROCESS_CAPABILITY_NONE);
@@ -354,8 +360,8 @@
         Thread.sleep(50);
         mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
                 ActivityManager.PROCESS_CAPABILITY_NONE);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
-                .isNotEqualTo(MODE_ALLOWED);
+        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+                false, null)).isNotEqualTo(MODE_ALLOWED);
     }
 
     @Test
@@ -363,13 +369,13 @@
         setupProcStateTests();
         mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
                 ActivityManager.PROCESS_CAPABILITY_NONE);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
-                .isNotEqualTo(MODE_ALLOWED);
+        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+                false, null)).isNotEqualTo(MODE_ALLOWED);
 
         mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
                 ActivityManager.PROCESS_CAPABILITY_NONE);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
-                .isNotEqualTo(MODE_ALLOWED);
+        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+                false, null)).isNotEqualTo(MODE_ALLOWED);
     }
 
     @Test
@@ -378,13 +384,13 @@
 
         mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
                 ActivityManager.PROCESS_CAPABILITY_NONE);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
-                .isNotEqualTo(MODE_ALLOWED);
+        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+                false, null)).isNotEqualTo(MODE_ALLOWED);
 
         mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
                 ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
-                .isEqualTo(MODE_ALLOWED);
+        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+                false, null)).isEqualTo(MODE_ALLOWED);
     }
 
     @Test
@@ -393,13 +399,13 @@
 
         mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
                 ActivityManager.PROCESS_CAPABILITY_NONE);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
-                .isNotEqualTo(MODE_ALLOWED);
+        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+                false, null)).isNotEqualTo(MODE_ALLOWED);
 
         mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP,
                 ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
-                .isEqualTo(MODE_ALLOWED);
+        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+                false, null)).isEqualTo(MODE_ALLOWED);
 
         mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
                 ActivityManager.PROCESS_CAPABILITY_NONE);
@@ -407,8 +413,8 @@
         Thread.sleep(50);
         mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
                 ActivityManager.PROCESS_CAPABILITY_NONE);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
-                .isNotEqualTo(MODE_ALLOWED);
+        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+                false, null)).isNotEqualTo(MODE_ALLOWED);
     }
 
     @Test
@@ -417,13 +423,13 @@
 
         mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
                 ActivityManager.PROCESS_CAPABILITY_NONE);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
-                .isNotEqualTo(MODE_ALLOWED);
+        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+                false, null)).isNotEqualTo(MODE_ALLOWED);
 
         mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP,
                 ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
-                .isEqualTo(MODE_ALLOWED);
+        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+                false, null)).isEqualTo(MODE_ALLOWED);
 
         mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
                 ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
@@ -431,8 +437,8 @@
         Thread.sleep(50);
         mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
                 ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
-                .isEqualTo(MODE_ALLOWED);
+        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+                false, null)).isEqualTo(MODE_ALLOWED);
 
         mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
                 ActivityManager.PROCESS_CAPABILITY_NONE);
@@ -440,8 +446,8 @@
         Thread.sleep(50);
         mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE,
                 ActivityManager.PROCESS_CAPABILITY_NONE);
-        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null))
-                .isNotEqualTo(MODE_ALLOWED);
+        assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName, null,
+                false, null)).isNotEqualTo(MODE_ALLOWED);
     }
 
     private List<PackageOps> getLoggedOps() {
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index d34f783..bbc6bdb 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -26,6 +26,11 @@
         <option name="test-file-name" value="SimpleServiceTestApp.apk" />
     </target_preparer>
 
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="AppIntegrityManagerServiceTestApp.apk->/data/local/tmp/AppIntegrityManagerServiceTestApp.apk" />
+    </target_preparer>
+
     <option name="test-tag" value="FrameworksServicesTests" />
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.frameworks.servicestests" />
diff --git a/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/test.apk b/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/test.apk
deleted file mode 100644
index 6345c98..0000000
--- a/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/test.apk
+++ /dev/null
Binary files differ
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 2ce17a1..f8bcff5 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -485,7 +485,7 @@
     @Test
     public void testDispatchUids_dispatchNeededChanges() throws RemoteException {
         when(mAppOpsService.noteOperation(AppOpsManager.OP_GET_USAGE_STATS, Process.myUid(), null,
-                null)).thenReturn(AppOpsManager.MODE_ALLOWED);
+                null, false, null)).thenReturn(AppOpsManager.MODE_ALLOWED);
 
         final int[] changesToObserve = {
             ActivityManager.UID_OBSERVER_PROCSTATE,
diff --git a/services/tests/servicestests/src/com/android/server/backup/internal/BackupHandlerTest.java b/services/tests/servicestests/src/com/android/server/backup/internal/BackupHandlerTest.java
new file mode 100644
index 0000000..fa35e3f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/backup/internal/BackupHandlerTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.backup.internal;
+
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertThrows;
+import static org.testng.Assert.assertTrue;
+
+import android.os.HandlerThread;
+import android.os.Message;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.backup.BackupAgentTimeoutParameters;
+import com.android.server.backup.UserBackupManagerService;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class BackupHandlerTest {
+    private static final int MESSAGE_TIMEOUT_MINUTES = 1;
+
+    @Mock private UserBackupManagerService mUserBackupManagerService;
+    @Mock private BackupAgentTimeoutParameters mTimeoutParameters;
+
+    private HandlerThread mHandlerThread;
+    private CountDownLatch mCountDownLatch;
+    private boolean mExceptionPropagated;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(/* testClass */ this);
+        when(mUserBackupManagerService.getAgentTimeoutParameters()).thenReturn(mTimeoutParameters);
+
+        mExceptionPropagated = false;
+        mCountDownLatch = new CountDownLatch(/* count */ 1);
+        mHandlerThread = new HandlerThread("BackupHandlerTestThread");
+        mHandlerThread.start();
+    }
+
+    @After
+    public void tearDown() {
+        mHandlerThread.quit();
+    }
+
+    @Test
+    public void testSendMessage_propagatesExceptions() throws Exception {
+        BackupHandler handler = new TestBackupHandler(/* shouldStop */ false);
+        handler.sendMessage(getMessage());
+        mCountDownLatch.await(MESSAGE_TIMEOUT_MINUTES, TimeUnit.MINUTES);
+
+        assertTrue(mExceptionPropagated);
+    }
+
+    @Test
+    public void testPost_propagatesExceptions() throws Exception {
+        BackupHandler handler = new TestBackupHandler(/* shouldStop */ false);
+        handler.post(() -> {});
+        mCountDownLatch.await(MESSAGE_TIMEOUT_MINUTES, TimeUnit.MINUTES);
+
+        assertTrue(mExceptionPropagated);
+    }
+
+    @Test
+    public void testSendMessage_stopping_doesntPropagateExceptions() throws Exception {
+        BackupHandler handler = new TestBackupHandler(/* shouldStop */ true);
+        handler.sendMessage(getMessage());
+        mCountDownLatch.await(MESSAGE_TIMEOUT_MINUTES, TimeUnit.MINUTES);
+
+        assertFalse(mExceptionPropagated);
+    }
+
+    @Test
+    public void testPost_stopping_doesntPropagateExceptions() throws Exception {
+        BackupHandler handler = new TestBackupHandler(/* shouldStop */ true);
+        handler.post(() -> {});
+        mCountDownLatch.await(MESSAGE_TIMEOUT_MINUTES, TimeUnit.MINUTES);
+
+        assertFalse(mExceptionPropagated);
+    }
+
+    private static Message getMessage() {
+        Message message = Message.obtain();
+        message.what = -1;
+        return message;
+    }
+
+    private class TestBackupHandler extends BackupHandler  {
+        private final boolean mShouldStop;
+
+        TestBackupHandler(boolean shouldStop) {
+            super(mUserBackupManagerService, mHandlerThread);
+
+            mShouldStop = shouldStop;
+        }
+
+        @Override
+        public void dispatchMessage(Message msg) {
+            try {
+                super.dispatchMessage(msg);
+            } catch (Exception e) {
+                mExceptionPropagated = true;
+            } finally {
+                mCountDownLatch.countDown();
+            }
+        }
+
+        @Override
+        void dispatchMessageInternal(Message msg) {
+            mIsStopping = mShouldStop;
+            throw new RuntimeException();
+        }
+    }
+}
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 4fcfa32..133d35d 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3659,6 +3659,25 @@
         assertExpectException(SecurityException.class, null, () -> dpm.setTime(admin1, 0));
     }
 
+    public void testSetTimeWithPOOfOrganizationOwnedDevice() throws Exception {
+        setupProfileOwner();
+        configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+        dpm.setTime(admin1, 0);
+
+        BaseMatcher<ManualTimeSuggestion> hasZeroTime = new BaseMatcher<ManualTimeSuggestion>() {
+            @Override
+            public boolean matches(Object item) {
+                final ManualTimeSuggestion suggestion = (ManualTimeSuggestion) item;
+                return suggestion.getUtcTime().getValue() == 0;
+            }
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("ManualTimeSuggestion{utcTime.value=0}");
+            }
+        };
+        verify(getServices().timeDetector).suggestManualTime(argThat(hasZeroTime));
+    }
+
     public void testSetTimeWithAutoTimeOn() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
@@ -3682,6 +3701,15 @@
                 () -> dpm.setTimeZone(admin1, "Asia/Shanghai"));
     }
 
+    public void testSetTimeZoneWithPOOfOrganizationOwnedDevice() throws Exception {
+        setupProfileOwner();
+        configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+        dpm.setTimeZone(admin1, "Asia/Shanghai");
+        ManualTimeZoneSuggestion suggestion =
+                TimeZoneDetector.createManualTimeZoneSuggestion("Asia/Shanghai", "Test debug info");
+        verify(getServices().timeZoneDetector).suggestManualTimeZone(suggestion);
+    }
+
     public void testSetTimeZoneWithAutoTimeZoneOn() throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 1a67576..960f670 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -217,6 +217,8 @@
                 return mMockSystemServices.wifiManager;
             case Context.ACCOUNT_SERVICE:
                 return mMockSystemServices.accountManager;
+            case Context.TELEPHONY_SERVICE:
+                return mMockSystemServices.telephonyManager;
         }
         throw new UnsupportedOperationException();
     }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
index 17e5832..09a6819 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
@@ -17,7 +17,6 @@
 
 import com.google.common.base.Objects;
 
-import com.android.internal.util.Preconditions;
 import com.android.server.pm.UserRestrictionsUtils;
 
 import android.content.ComponentName;
@@ -107,7 +106,7 @@
     }
 
     public static Bundle checkUserRestrictions(String... keys) {
-        final Bundle expected = DpmTestUtils.newRestrictions(Preconditions.checkNotNull(keys));
+        final Bundle expected = DpmTestUtils.newRestrictions(java.util.Objects.requireNonNull(keys));
         final Matcher<Bundle> m = new BaseMatcher<Bundle>() {
             @Override
             public boolean matches(Object item) {
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index a2376a6..604efc4 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -32,6 +32,7 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -64,7 +65,6 @@
 import com.android.server.integrity.model.IntegrityCheckResult;
 import com.android.server.testutils.TestUtils;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -75,9 +75,6 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.StandardCopyOption;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -86,7 +83,8 @@
 /** Unit test for {@link com.android.server.integrity.AppIntegrityManagerServiceImpl} */
 @RunWith(AndroidJUnit4.class)
 public class AppIntegrityManagerServiceImplTest {
-    private static final String TEST_DIR = "AppIntegrityManagerServiceImplTest";
+    private static final String TEST_APP_PATH =
+            "/data/local/tmp/AppIntegrityManagerServiceTestApp.apk";
 
     private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
     private static final String VERSION = "version";
@@ -97,13 +95,19 @@
     private static final String INSTALLER = TEST_FRAMEWORK_PACKAGE;
     // These are obtained by running the test and checking logcat.
     private static final String APP_CERT =
-            "949ADC6CB92FF09E3784D6E9504F26F9BEAC06E60D881D55A6A81160F9CD6FD1";
+            "301AA3CB081134501C45F1422ABC66C24224FD5DED5FDC8F17E697176FD866AA";
     private static final String INSTALLER_CERT =
             "301AA3CB081134501C45F1422ABC66C24224FD5DED5FDC8F17E697176FD866AA";
     // We use SHA256 for package names longer than 32 characters.
     private static final String INSTALLER_SHA256 =
             "786933C28839603EB48C50B2A688DC6BE52C833627CB2731FF8466A2AE9F94CD";
 
+    private static final String PLAY_STORE_PKG = "com.android.vending";
+    private static final String ADB_INSTALLER = "adb";
+    private static final String PLAY_STORE_CERT =
+            "play_store_cert";
+    private static final String ADB_CERT = "";
+
     @org.junit.Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
 
     @Mock PackageManagerInternal mPackageManagerInternal;
@@ -122,11 +126,7 @@
 
     @Before
     public void setup() throws Exception {
-        mTestApk = File.createTempFile("TestApk", /* suffix= */ null);
-        mTestApk.deleteOnExit();
-        try (InputStream inputStream = mRealContext.getAssets().open(TEST_DIR + "/test.apk")) {
-            Files.copy(inputStream, mTestApk.toPath(), StandardCopyOption.REPLACE_EXISTING);
-        }
+        mTestApk = new File(TEST_APP_PATH);
 
         mService =
                 new AppIntegrityManagerServiceImpl(
@@ -141,11 +141,7 @@
         when(mMockContext.getPackageManager()).thenReturn(mSpyPackageManager);
         when(mMockContext.getResources()).thenReturn(mMockResources);
         when(mMockResources.getStringArray(anyInt())).thenReturn(new String[] {});
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        mTestApk.delete();
+        when(mIntegrityFileManager.initialized()).thenReturn(true);
     }
 
     // This is not a test of the class, but more of a safeguard that we don't block any install in
@@ -310,10 +306,10 @@
         assertEquals(INSTALLER_CERT, appInstallMetadata.getInstallerCertificate());
         assertEquals(VERSION_CODE, appInstallMetadata.getVersionCode());
         assertFalse(appInstallMetadata.isPreInstalled());
-        // These are hardcoded in the test apk
+        // These are hardcoded in the test apk android manifest
         assertEquals(2, allowedInstallers.size());
-        assertEquals("cert_1", allowedInstallers.get("store_1"));
-        assertEquals("cert_2", allowedInstallers.get("store_2"));
+        assertEquals(PLAY_STORE_CERT, allowedInstallers.get(PLAY_STORE_PKG));
+        assertEquals(ADB_CERT, allowedInstallers.get(ADB_INSTALLER));
     }
 
     @Test
@@ -356,6 +352,25 @@
                         1, PackageManagerInternal.INTEGRITY_VERIFICATION_REJECT);
     }
 
+    @Test
+    public void handleBroadcast_notInitialized() throws Exception {
+        when(mIntegrityFileManager.initialized()).thenReturn(false);
+        ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
+        verify(mMockContext)
+                .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
+        Intent intent = makeVerificationIntent();
+        when(mRuleEvaluationEngine.evaluate(any(), any())).thenReturn(IntegrityCheckResult.allow());
+
+        broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
+        runJobInHandler();
+
+        verify(mPackageManagerInternal)
+                .setIntegrityVerificationResult(
+                        1, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
+        verify(mSpyPackageManager, never()).getPackageArchiveInfo(any(), anyInt());
+    }
+
     private void whitelistUsAsRuleProvider() {
         Resources mockResources = mock(Resources.class);
         when(mockResources.getStringArray(R.array.config_integrityRuleProviderPackages))
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 f9fc3a1..41416f1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -88,7 +88,6 @@
 import android.util.Log;
 import android.util.Pair;
 
-import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.pm.LauncherAppsService.LauncherAppsImpl;
@@ -114,6 +113,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.function.BiFunction;
 import java.util.function.BiPredicate;
@@ -1241,7 +1241,7 @@
     protected void setCaller(String packageName, int userId) {
         mInjectedClientPackage = packageName;
         mInjectedCallingUid =
-                Preconditions.checkNotNull(getInjectedPackageInfo(packageName, userId, false),
+                Objects.requireNonNull(getInjectedPackageInfo(packageName, userId, false),
                         "Unknown package").applicationInfo.uid;
 
         // Set up LauncherApps for this caller.
diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java
index aec489c..757a884 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java
@@ -53,8 +53,7 @@
                     if (a == null || b == null) {
                         return a == b;
                     }
-                    return a.getLongVersionCode() == b.getLongVersionCode()
-                            && Objects.equals(a.getPackageName(), b.getPackageName());
+                    return a.equals(b);
                 }
 
                 @Override
@@ -298,15 +297,8 @@
     private void assertPackageRollbacksAreEquivalent(PackageRollbackInfo b, PackageRollbackInfo a) {
         assertThat(b.getPackageName()).isEqualTo(a.getPackageName());
 
-        assertThat(b.getVersionRolledBackFrom().getLongVersionCode())
-                .isEqualTo(a.getVersionRolledBackFrom().getLongVersionCode());
-        assertThat(b.getVersionRolledBackFrom().getPackageName())
-                .isEqualTo(a.getVersionRolledBackFrom().getPackageName());
-
-        assertThat(b.getVersionRolledBackTo().getLongVersionCode())
-                .isEqualTo(a.getVersionRolledBackTo().getLongVersionCode());
-        assertThat(b.getVersionRolledBackTo().getPackageName())
-                .isEqualTo(a.getVersionRolledBackTo().getPackageName());
+        assertThat(b.getVersionRolledBackFrom()).isEqualTo(a.getVersionRolledBackFrom());
+        assertThat(b.getVersionRolledBackTo()).isEqualTo(a.getVersionRolledBackTo());
 
         assertThat(b.getPendingBackups().toArray()).isEqualTo(a.getPendingBackups().toArray());
 
diff --git a/services/tests/servicestests/test-apps/AppIntegrityManagerServiceTestApp/Android.bp b/services/tests/servicestests/test-apps/AppIntegrityManagerServiceTestApp/Android.bp
new file mode 100644
index 0000000..9aaa37d
--- /dev/null
+++ b/services/tests/servicestests/test-apps/AppIntegrityManagerServiceTestApp/Android.bp
@@ -0,0 +1,21 @@
+// 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.
+
+android_test_helper_app {
+    name: "AppIntegrityManagerServiceTestApp",
+
+    test_suites: ["device-tests"],
+
+    certificate: "platform",
+}
diff --git a/services/tests/servicestests/test-apps/AppIntegrityManagerServiceTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/AppIntegrityManagerServiceTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..f5dbf43
--- /dev/null
+++ b/services/tests/servicestests/test-apps/AppIntegrityManagerServiceTestApp/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 Google Inc.
+ *
+ * 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.google.android.appintegritymanager.test.app"
+    android:versionCode="5000">
+
+    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="28" />
+
+    <application android:hasCode="false">
+        <meta-data android:name="allowed-installers" android:value="com.android.vending|play_store_cert,adb|"/>
+    </application>
+</manifest>
+
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 d6bd1d0..73b2f6b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -902,7 +902,7 @@
         topActivity.mVisibleRequested = false;
         topActivity.nowVisible = false;
         topActivity.finishing = true;
-        topActivity.setState(PAUSED, "true");
+        topActivity.setState(STOPPED, "true");
         // Mark the bottom activity as not visible, so that we would wait for it before removing
         // the top one.
         mActivity.mVisibleRequested = false;
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 c24ce2b..a5157fe9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -236,7 +236,7 @@
         // Overlay must be for a different user to prevent recognizing a matching top activity
         final ActivityRecord taskOverlay = new ActivityBuilder(mService).setTask(task)
                 .setUid(UserHandle.PER_USER_RANGE * 2).build();
-        taskOverlay.mTaskOverlay = true;
+        taskOverlay.setTaskOverlay(true);
 
         final RootWindowContainer.FindTaskResult result =
                 new RootWindowContainer.FindTaskResult();
@@ -574,6 +574,27 @@
     }
 
     @Test
+    public void testShouldBeVisible_FullscreenBehindTranslucentInHomeStack() {
+        final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
+
+        final ActivityRecord firstActivity = new ActivityBuilder(mService)
+                    .setStack(homeStack)
+                    .setCreateTask(true)
+                    .build();
+        final Task task = firstActivity.getTask();
+        final ActivityRecord secondActivity = new ActivityBuilder(mService)
+                .setTask(task)
+                .build();
+
+        doReturn(false).when(secondActivity).occludesParent();
+        homeStack.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
+                false /* preserveWindows */);
+
+        assertTrue(firstActivity.shouldBeVisible());
+    }
+
+    @Test
     public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeBehindFullscreen() {
         mDefaultDisplay.removeStack(mStack);
 
@@ -865,7 +886,7 @@
                 .setComponent(new ComponentName("package.overlay", ".OverlayActivity")).build();
         // If the task only remains overlay activity, the task should also be removed.
         // See {@link ActivityStack#removeFromHistory}.
-        overlayActivity.mTaskOverlay = true;
+        overlayActivity.setTaskOverlay(true);
 
         // The activity without an app means it will be removed immediately.
         // See {@link ActivityStack#destroyActivityLocked}.
@@ -893,7 +914,7 @@
         // Making the first activity a task overlay means it will be removed from the task's
         // activities as well once second activity is removed as handleAppDied processes the
         // activity list in reverse.
-        firstActivity.mTaskOverlay = true;
+        firstActivity.setTaskOverlay(true);
         firstActivity.app = null;
 
         // second activity will be immediately removed as it has no state.
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 b1132f6..9e54f40 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -33,8 +33,10 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
+import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations;
@@ -433,32 +435,28 @@
     }
 
     /**
-     * This test ensures that if the intent is being delivered to a
+     * This test ensures that if the intent is being delivered to a split-screen unfocused task
+     * while it already on top, reports it as delivering to top.
      */
     @Test
     public void testSplitScreenDeliverToTop() {
-        final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-
-        final ActivityRecord focusActivity = new ActivityBuilder(mService)
-                .setCreateTask(true)
-                .build();
-
-        focusActivity.getActivityStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
-
-        final ActivityRecord reusableActivity = new ActivityBuilder(mService)
-                .setCreateTask(true)
-                .build();
-
-        // Create reusable activity after entering split-screen so that it is the top secondary
-        // stack.
-        reusableActivity.getActivityStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+        final ActivityStarter starter = prepareStarter(
+                FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false);
+        final ActivityRecord splitPrimaryFocusActivity =
+                new ActivityBuilder(mService).setCreateTask(true).build();
+        final ActivityRecord splitSecondReusableActivity =
+                new ActivityBuilder(mService).setCreateTask(true).build();
+        splitPrimaryFocusActivity.getActivityStack()
+                .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+        splitSecondReusableActivity.getActivityStack()
+                .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
 
         // Set focus back to primary.
-        final ActivityStack focusStack = focusActivity.getActivityStack();
-        focusStack.moveToFront("testSplitScreenDeliverToTop");
+        splitPrimaryFocusActivity.getActivityStack().moveToFront("testSplitScreenDeliverToTop");
 
-        doReturn(reusableActivity).when(mRootWindowContainer).findTask(any(), anyInt());
-
+        // Start activity and delivered new intent.
+        starter.getIntent().setComponent(splitSecondReusableActivity.mActivityComponent);
+        doReturn(splitSecondReusableActivity).when(mRootWindowContainer).findTask(any(), anyInt());
         final int result = starter.setReason("testSplitScreenDeliverToTop").execute();
 
         // Ensure result is delivering intent to top.
@@ -471,26 +469,30 @@
      */
     @Test
     public void testSplitScreenTaskToFront() {
-        final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+        final ActivityStarter starter = prepareStarter(
+                FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false);
+        final ActivityRecord splitSecondReusableActivity =
+                new ActivityBuilder(mService).setCreateTask(true).build();
+        final ActivityRecord splitSecondTopActivity =
+                new ActivityBuilder(mService).setCreateTask(true).build();
+        final ActivityRecord splitPrimaryFocusActivity =
+                new ActivityBuilder(mService).setCreateTask(true).build();
+        splitPrimaryFocusActivity.getActivityStack()
+                .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+        splitSecondReusableActivity.getActivityStack()
+                .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+        splitSecondTopActivity.getActivityStack()
+                .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
 
-        // Create reusable activity here first. Setting the windowing mode of the primary stack
-        // will move the existing standard full screen stack to secondary, putting this one on the
-        // bottom.
-        final ActivityRecord reusableActivity = new ActivityBuilder(mService)
-                .setCreateTask(true)
-                .build();
+        // Make it on top of split-screen-secondary.
+        splitSecondTopActivity.getActivityStack().moveToFront("testSplitScreenTaskToFront");
 
-        reusableActivity.getActivityStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+        // Let primary stack has focus.
+        splitPrimaryFocusActivity.getActivityStack().moveToFront("testSplitScreenTaskToFront");
 
-        final ActivityRecord focusActivity = new ActivityBuilder(mService)
-                .setCreateTask(true)
-                .build();
-
-        // Enter split-screen. Primary stack should have focus.
-        focusActivity.getActivityStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
-
-        doReturn(reusableActivity).when(mRootWindowContainer).findTask(any(), anyInt());
-
+        // Start activity and delivered new intent.
+        starter.getIntent().setComponent(splitSecondReusableActivity.mActivityComponent);
+        doReturn(splitSecondReusableActivity).when(mRootWindowContainer).findTask(any(), anyInt());
         final int result = starter.setReason("testSplitScreenMoveToFront").execute();
 
         // Ensure result is moving task to front.
@@ -979,4 +981,29 @@
         assertThat(result == START_SUCCESS).isTrue();
         assertThat(starter.mAddingToTask).isTrue();
     }
+
+    @Test
+    public void testTargetStackInSplitScreen() {
+        final ActivityStarter starter =
+                prepareStarter(FLAG_ACTIVITY_LAUNCH_ADJACENT, false /* mockGetLaunchStack */);
+        final ActivityRecord top = new ActivityBuilder(mService).setCreateTask(true).build();
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        final ActivityRecord[] outActivity = new ActivityRecord[1];
+
+        // Activity must not land on split-screen stack if currently not in split-screen mode.
+        starter.setActivityOptions(options.toBundle())
+                .setReason("testWindowingModeOptionsLaunchAdjacent")
+                .setOutActivity(outActivity).execute();
+        assertThat(outActivity[0].inSplitScreenWindowingMode()).isFalse();
+
+        // Move activity to split-screen-primary stack and make sure it has the focus.
+        top.getActivityStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+        top.getActivityStack().moveToFront("testWindowingModeOptionsLaunchAdjacent");
+
+        // Activity must landed on split-screen-secondary when launch adjacent.
+        starter.setActivityOptions(options.toBundle())
+                .setReason("testWindowingModeOptionsLaunchAdjacent")
+                .setOutActivity(outActivity).execute();
+        assertThat(outActivity[0].inSplitScreenSecondaryWindowingMode()).isTrue();
+    }
 }
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 a39be56..574517a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
@@ -28,11 +28,11 @@
 
 import android.platform.test.annotations.Presubmit;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -44,6 +44,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class AnimatingActivityRegistryTest extends WindowTestsBase {
 
     @Mock
@@ -60,7 +61,6 @@
     }
 
     @Test
-    @FlakyTest(bugId = 144611135)
     public void testDeferring() {
         final ActivityRecord activity1 = createActivityRecord(mDisplayContent,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
@@ -83,7 +83,6 @@
     }
 
     @Test
-    @FlakyTest(bugId = 131005232)
     public void testContainerRemoved() {
         final ActivityRecord window1 = createActivityRecord(mDisplayContent,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
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 fc94c5e..8c2b293 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -61,7 +61,7 @@
     public void setUpOnDisplay(DisplayContent dc) {
         mActivity = createTestActivityRecord(dc, WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD);
         mTask = mActivity.getTask();
-        mStack = mTask.getTaskStack();
+        mStack = mTask.getStack();
 
         // Set a remote animator with snapshot disabled. Snapshots don't work in wmtests.
         RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 0758eeb..73dd2df 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -126,7 +126,7 @@
         waitUntilHandlersIdle();
 
         exitingApp.mIsExiting = true;
-        exitingApp.getTask().getTaskStack().mExitingActivities.add(exitingApp);
+        exitingApp.getTask().getStack().mExitingActivities.add(exitingApp);
 
         assertForAllWindowsOrder(Arrays.asList(
                 mWallpaperWindow,
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
index 31b658a..cf1f0a8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -424,7 +424,7 @@
         void saveTask(Task task) {
             final int userId = task.mUserId;
             final ComponentName realActivity = task.realActivity;
-            mTmpParams.mPreferredDisplayId = task.getStack().mDisplayId;
+            mTmpParams.mPreferredDisplayId = task.getDisplayId();
             mTmpParams.mWindowingMode = task.getWindowingMode();
             if (task.mLastNonFullscreenBounds != null) {
                 mTmpParams.mBounds.set(task.mLastNonFullscreenBounds);
diff --git a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
index 103c3ab..f007149 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
@@ -24,12 +24,13 @@
 import android.platform.test.annotations.Presubmit;
 import android.view.RemoteAnimationAdapter;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
+import com.android.server.AnimationThread;
 import com.android.server.testutils.OffsettableClock;
 import com.android.server.testutils.TestHandler;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
@@ -41,7 +42,7 @@
  */
 @SmallTest
 @Presubmit
-public class PendingRemoteAnimationRegistryTest extends ActivityTestsBase {
+public class PendingRemoteAnimationRegistryTest {
 
     @Mock RemoteAnimationAdapter mAdapter;
     private PendingRemoteAnimationRegistry mRegistry;
@@ -51,10 +52,15 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mService.mH.runWithScissors(() -> {
+        AnimationThread.getHandler().runWithScissors(() -> {
             mHandler = new TestHandler(null, mClock);
         }, 0);
-        mRegistry = new PendingRemoteAnimationRegistry(mService, mHandler);
+        mRegistry = new PendingRemoteAnimationRegistry(new WindowManagerGlobalLock(), mHandler);
+    }
+
+    @After
+    public void teadDown() {
+        AnimationThread.dispose();
     }
 
     @Test
@@ -74,7 +80,6 @@
     }
 
     @Test
-    @FlakyTest(bugId = 131005232)
     public void testTimeout() {
         mRegistry.addPendingAnimation("com.android.test", mAdapter);
         mClock.fastForward(5000);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 55a139a..79f808e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -421,6 +421,7 @@
     @Test
     public void testUsersTasks() {
         mRecentTasks.setOnlyTestVisibleRange();
+        mRecentTasks.unloadUserDataFromMemoryLocked(TEST_USER_0_ID);
 
         // Setup some tasks for the users
         mTaskPersister.mUserTaskIdsOverride = new SparseBooleanArray();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 9f092835..04d79ca 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -857,7 +857,7 @@
         // Assert that the stack is returned as expected.
         assertNotNull(result);
         assertEquals("The display ID of the stack should same as secondary display ",
-                secondaryDisplay.mDisplayId, result.mDisplayId);
+                secondaryDisplay.mDisplayId, result.getDisplayId());
     }
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index f90eca3..05d1c76 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -433,7 +433,7 @@
             doReturn(aos).when(this).getAppOpsService();
             // Make sure permission checks aren't overridden.
             doReturn(AppOpsManager.MODE_DEFAULT).when(aos).noteOperation(anyInt(), anyInt(),
-                    anyString(), nullable(String.class));
+                    anyString(), nullable(String.class), anyBoolean(), nullable(String.class));
 
             // UserManagerService
             final UserManagerService ums = mock(UserManagerService.class);
@@ -484,8 +484,8 @@
             spyOn(this);
 
             // Do not schedule idle that may touch methods outside the scope of the test.
-            doNothing().when(this).scheduleIdleLocked();
-            doNothing().when(this).scheduleIdleTimeoutLocked(any());
+            doNothing().when(this).scheduleIdle();
+            doNothing().when(this).scheduleIdleTimeout(any());
             // unit test version does not handle launch wake lock
             doNothing().when(this).acquireLaunchWakelock();
             doReturn(mock(KeyguardController.class)).when(this).getKeyguardController();
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 9f2bfa7..9562fa4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -345,6 +345,7 @@
         spyOn(parentWindowContainer);
         parentWindowContainer.setBounds(fullScreenBounds);
         doReturn(parentWindowContainer).when(task).getParent();
+        doReturn(stack).when(task).getStack();
         doReturn(true).when(parentWindowContainer).handlesOrientationChangeFromDescendant();
 
         // Setting app to fixed portrait fits within parent, but Task shouldn't adjust the
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 6c3410a..b4f5751 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -110,12 +110,12 @@
     public void testStackRemoveImmediately() {
         final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(stack, 0 /* userId */);
-        assertEquals(stack, task.getTaskStack());
+        assertEquals(stack, task.getStack());
 
         // Remove stack and check if its child is also removed.
         stack.removeImmediately();
         assertNull(stack.getDisplayContent());
-        assertNull(task.getTaskStack());
+        assertNull(task.getStack());
     }
 
     @Test
@@ -131,7 +131,7 @@
         assertEquals(0, stack.getChildCount());
         assertNull(stack.getDisplayContent());
         assertNull(task.getDisplayContent());
-        assertNull(task.getTaskStack());
+        assertNull(task.getStack());
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 634d2f0..08ee0eb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -80,11 +80,6 @@
     }
 
     @Override
-    public boolean checkShowToOwnerOnly(WindowManager.LayoutParams attrs) {
-        return false;
-    }
-
-    @Override
     public void adjustConfigurationLw(Configuration config, int keyboardPresence,
             int navigationPresence) {
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 6d23b2e..5028585 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -522,7 +522,8 @@
     public void testVisibilityChangeSwitchUser() {
         final WindowState window = createWindow(null, TYPE_APPLICATION, "app");
         window.mHasSurface = true;
-        window.setShowToOwnerOnlyLocked(true);
+        spyOn(window);
+        doReturn(false).when(window).showForAllUsers();
 
         mWm.mCurrentUserId = 1;
         window.switchUser(mWm.mCurrentUserId);
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 0a6183c..599cd9f 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -379,15 +379,15 @@
     /**
      * Create a new ServiceState from a intent notifier Bundle
      *
-     * This method is used by PhoneStateIntentReceiver, CellBroadcastReceiver, and maybe by
-     * external applications.
+     * This method is used to get ServiceState object from extras upon receiving
+     * {@link Intent#ACTION_SERVICE_STATE}.
      *
      * @param m Bundle from intent notifier
      * @return newly created ServiceState
      * @hide
      */
+    @SystemApi
     @NonNull
-    @UnsupportedAppUsage
     public static ServiceState newFromBundle(@NonNull Bundle m) {
         ServiceState ret;
         ret = new ServiceState();
@@ -1281,11 +1281,15 @@
     /**
      * Set intent notifier Bundle based on service state.
      *
+     * Put ServiceState object and its fields into bundle which is used by TelephonyRegistry
+     * to broadcast {@link Intent#ACTION_SERVICE_STATE}.
+     *
      * @param m intent notifier Bundle
      * @hide
+     *
      */
-    @UnsupportedAppUsage
-    public void fillInNotifierBundle(Bundle m) {
+    @SystemApi
+    public void fillInNotifierBundle(@NonNull Bundle m) {
         m.putParcelable(Intent.EXTRA_SERVICE_STATE, this);
         // serviceState already consists of below entries.
         // for backward compatibility, we continue fill in below entries.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index deafbb3..20c9f6c 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -17,6 +17,8 @@
 package android.telephony;
 
 import static android.content.Context.TELECOM_SERVICE;
+import static android.provider.Telephony.Carriers.DPC_URI;
+import static android.provider.Telephony.Carriers.INVALID_APN_ID;
 
 import static com.android.internal.util.Preconditions.checkNotNull;
 
@@ -44,6 +46,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.database.Cursor;
 import android.net.ConnectivityManager;
 import android.net.NetworkStats;
 import android.net.Uri;
@@ -75,6 +78,7 @@
 import android.telephony.Annotation.SimActivationState;
 import android.telephony.Annotation.UiccAppType;
 import android.telephony.VisualVoicemailService.VisualVoicemailTask;
+import android.telephony.data.ApnSetting;
 import android.telephony.data.ApnSetting.MvnoType;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories;
@@ -8201,9 +8205,9 @@
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.supplyPin(pin);
+                return telephony.supplyPinForSubscriber(getSubId(), pin);
         } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#supplyPin", e);
+            Log.e(TAG, "Error calling ITelephony#supplyPinForSubscriber", e);
         }
         return false;
     }
@@ -8215,9 +8219,9 @@
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.supplyPuk(puk, pin);
+                return telephony.supplyPukForSubscriber(getSubId(), puk, pin);
         } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#supplyPuk", e);
+            Log.e(TAG, "Error calling ITelephony#supplyPukForSubscriber", e);
         }
         return false;
     }
@@ -8229,9 +8233,9 @@
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.supplyPinReportResult(pin);
+                return telephony.supplyPinReportResultForSubscriber(getSubId(), pin);
         } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#supplyPinReportResult", e);
+            Log.e(TAG, "Error calling ITelephony#supplyPinReportResultForSubscriber", e);
         }
         return new int[0];
     }
@@ -8243,7 +8247,7 @@
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.supplyPukReportResult(puk, pin);
+                return telephony.supplyPukReportResultForSubscriber(getSubId(), puk, pin);
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#]", e);
         }
@@ -11860,6 +11864,88 @@
     }
 
     /**
+     * Returns a list of APNs set as overrides by the device policy manager via
+     * {@link #addDevicePolicyOverrideApn}.
+     * This method must only be called from the system or phone processes.
+     *
+     * @param context Context to use.
+     * @return {@link List} of APNs that have been set as overrides.
+     * @throws {@link SecurityException} if the caller is not the system or phone process.
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    // TODO: add new permission tag indicating that this is system-only.
+    public @NonNull List<ApnSetting> getDevicePolicyOverrideApns(@NonNull Context context) {
+        try (Cursor cursor = context.getContentResolver().query(DPC_URI, null, null, null, null)) {
+            if (cursor == null) {
+                return Collections.emptyList();
+            }
+            List<ApnSetting> apnList = new ArrayList<ApnSetting>();
+            cursor.moveToPosition(-1);
+            while (cursor.moveToNext()) {
+                ApnSetting apn = ApnSetting.makeApnSetting(cursor);
+                apnList.add(apn);
+            }
+            return apnList;
+        }
+    }
+
+    /**
+     * Used by the device policy manager to add a new override APN.
+     * This method must only be called from the system or phone processes.
+     *
+     * @param context Context to use.
+     * @param apnSetting The {@link ApnSetting} describing the new APN.
+     * @return An integer, corresponding to a primary key in a database, that allows the caller to
+     *         modify the APN in the future via {@link #modifyDevicePolicyOverrideApn}, or
+     *         {@link android.provider.Telephony.Carriers.INVALID_APN_ID} if the override operation
+     *         failed.
+     * @throws {@link SecurityException} if the caller is not the system or phone process.
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    // TODO: add new permission tag indicating that this is system-only.
+    public int addDevicePolicyOverrideApn(@NonNull Context context,
+            @NonNull ApnSetting apnSetting) {
+        Uri resultUri = context.getContentResolver().insert(DPC_URI, apnSetting.toContentValues());
+
+        int resultId = INVALID_APN_ID;
+        if (resultUri != null) {
+            try {
+                resultId = Integer.parseInt(resultUri.getLastPathSegment());
+            } catch (NumberFormatException e) {
+                Rlog.e(TAG, "Failed to parse inserted override APN id: "
+                        + resultUri.getLastPathSegment());
+            }
+        }
+        return resultId;
+    }
+
+    /**
+     * Used by the device policy manager to modify an override APN.
+     * This method must only be called from the system or phone processes.
+     *
+     * @param context Context to use.
+     * @param apnId The integer key of the APN to modify, as returned by
+     *              {@link #addDevicePolicyOverrideApn}
+     * @param apnSetting The {@link ApnSetting} describing the updated APN.
+     * @return {@code true} if successful, {@code false} otherwise.
+     * @throws {@link SecurityException} if the caller is not the system or phone process.
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    // TODO: add new permission tag indicating that this is system-only.
+    public boolean modifyDevicePolicyOverrideApn(@NonNull Context context, int apnId,
+            @NonNull ApnSetting apnSetting) {
+        return context.getContentResolver().update(
+                Uri.withAppendedPath(DPC_URI, Integer.toString(apnId)),
+                apnSetting.toContentValues(), null, null) > 0;
+    }
+
+    /**
      * Return whether data is enabled for certain APN type. This will tell if framework will accept
      * corresponding network requests on a subId.
      *
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 57fda9b1..9d721fc 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -117,13 +117,6 @@
      */
     boolean isRadioOnForSubscriberWithFeature(int subId, String callingPackage, String callingFeatureId);
 
-    /**
-     * Supply a pin to unlock the SIM.  Blocks until a result is determined.
-     * @param pin The pin to check.
-     * @return whether the operation was a success.
-     */
-    @UnsupportedAppUsage
-    boolean supplyPin(String pin);
 
     /**
      * Supply a pin to unlock the SIM for particular subId.
@@ -139,15 +132,6 @@
      *  Blocks until a result is determined.
      * @param puk The puk to check.
      *        pin The new pin to be set in SIM
-     * @return whether the operation was a success.
-     */
-    boolean supplyPuk(String puk, String pin);
-
-    /**
-     * Supply puk to unlock the SIM and set SIM pin to new pin.
-     *  Blocks until a result is determined.
-     * @param puk The puk to check.
-     *        pin The new pin to be set in SIM
      * @param subId user preferred subId.
      * @return whether the operation was a success.
      */
@@ -160,15 +144,6 @@
      * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code
      *         retValue[1] = number of attempts remaining if known otherwise -1
      */
-    int[] supplyPinReportResult(String pin);
-
-    /**
-     * Supply a pin to unlock the SIM.  Blocks until a result is determined.
-     * Returns a specific success/error code.
-     * @param pin The pin to check.
-     * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code
-     *         retValue[1] = number of attempts remaining if known otherwise -1
-     */
     int[] supplyPinReportResultForSubscriber(int subId, String pin);
 
     /**
@@ -180,17 +155,6 @@
      * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code
      *         retValue[1] = number of attempts remaining if known otherwise -1
      */
-    int[] supplyPukReportResult(String puk, String pin);
-
-    /**
-     * Supply puk to unlock the SIM and set SIM pin to new pin.
-     * Blocks until a result is determined.
-     * Returns a specific success/error code
-     * @param puk The puk to check
-     *        pin The pin to check.
-     * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code
-     *         retValue[1] = number of attempts remaining if known otherwise -1
-     */
     int[] supplyPukReportResultForSubscriber(int subId, String puk, String pin);
 
     /**
diff --git a/tests/net/integration/AndroidManifest.xml b/tests/net/integration/AndroidManifest.xml
index 4dd3b5a..09c0e48 100644
--- a/tests/net/integration/AndroidManifest.xml
+++ b/tests/net/integration/AndroidManifest.xml
@@ -28,7 +28,9 @@
     <!-- Reading network status -->
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+    <uses-permission android:name="android.permission.NETWORK_FACTORY" />
+    <uses-permission android:name="android.permission.NETWORK_STACK" />
+    <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
     <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
     <!-- Reading DeviceConfig flags -->
     <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index b725920..27960c8 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -365,6 +365,8 @@
   });
   manifest_action["instrumentation"]["meta-data"] = meta_data_action;
 
+  manifest_action["feature"];
+  manifest_action["feature"]["inherit-from"];
   manifest_action["original-package"];
   manifest_action["overlay"];
   manifest_action["protected-broadcast"];
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 8155922..35a892a 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -69,6 +69,7 @@
         "//frameworks/base", // TODO(b/140299412) remove once all dependencies are fixed
         "//frameworks/opt/net/wifi/service:__subpackages__",
     ] + test_access_hidden_api_whitelist,
+    plugins: ["java_api_finder"],
 }
 
 droidstubs {
diff --git a/wifi/java/android/net/wifi/WifiClient.java b/wifi/java/android/net/wifi/WifiClient.java
index 3e09580..3794566 100644
--- a/wifi/java/android/net/wifi/WifiClient.java
+++ b/wifi/java/android/net/wifi/WifiClient.java
@@ -22,8 +22,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import com.android.internal.util.Preconditions;
-
 import java.util.Objects;
 
 /** @hide */
@@ -46,7 +44,7 @@
 
     /** @hide */
     public WifiClient(@NonNull MacAddress macAddress) {
-        Preconditions.checkNotNull(macAddress, "mMacAddress must not be null.");
+        Objects.requireNonNull(macAddress, "mMacAddress must not be null.");
 
         this.mMacAddress = macAddress;
     }
diff --git a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
index be37c22..378549d 100755
--- a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
+++ b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
@@ -29,11 +29,11 @@
 import android.util.LruCache;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * {@link INetworkScoreCache} implementation for Wifi Networks.
@@ -290,7 +290,7 @@
          *          This cannot be null.
          */
         public CacheListener(@NonNull Handler handler) {
-            Preconditions.checkNotNull(handler);
+            Objects.requireNonNull(handler);
             mHandler = handler;
         }
 
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 8badcc0..2c39c32a 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -40,7 +40,6 @@
 import android.util.SparseArray;
 
 import com.android.internal.util.AsyncChannel;
-import com.android.internal.util.Preconditions;
 import com.android.internal.util.Protocol;
 
 import java.lang.annotation.Retention;
@@ -48,6 +47,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.Executor;
 
 /**
@@ -840,8 +840,8 @@
     @RequiresPermission(Manifest.permission.NETWORK_STACK)
     public void registerScanListener(@NonNull @CallbackExecutor Executor executor,
             @NonNull ScanListener listener) {
-        Preconditions.checkNotNull(executor, "executor cannot be null");
-        Preconditions.checkNotNull(listener, "listener cannot be null");
+        Objects.requireNonNull(executor, "executor cannot be null");
+        Objects.requireNonNull(listener, "listener cannot be null");
         int key = addListener(listener, executor);
         if (key == INVALID_KEY) return;
         validateChannel();
@@ -864,7 +864,7 @@
      *  #registerScanListener}
      */
     public void unregisterScanListener(@NonNull ScanListener listener) {
-        Preconditions.checkNotNull(listener, "listener cannot be null");
+        Objects.requireNonNull(listener, "listener cannot be null");
         int key = removeListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
@@ -894,7 +894,7 @@
     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
     public void startBackgroundScan(ScanSettings settings, ScanListener listener,
             WorkSource workSource) {
-        Preconditions.checkNotNull(listener, "listener cannot be null");
+        Objects.requireNonNull(listener, "listener cannot be null");
         int key = addListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
@@ -913,7 +913,7 @@
      */
     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
     public void stopBackgroundScan(ScanListener listener) {
-        Preconditions.checkNotNull(listener, "listener cannot be null");
+        Objects.requireNonNull(listener, "listener cannot be null");
         int key = removeListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
@@ -962,7 +962,7 @@
      */
     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
     public void startScan(ScanSettings settings, ScanListener listener, WorkSource workSource) {
-        Preconditions.checkNotNull(listener, "listener cannot be null");
+        Objects.requireNonNull(listener, "listener cannot be null");
         int key = addListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
@@ -981,7 +981,7 @@
      */
     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
     public void stopScan(ScanListener listener) {
-        Preconditions.checkNotNull(listener, "listener cannot be null");
+        Objects.requireNonNull(listener, "listener cannot be null");
         int key = removeListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
@@ -1036,8 +1036,8 @@
      */
     public void startConnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings,
             PnoScanListener listener) {
-        Preconditions.checkNotNull(listener, "listener cannot be null");
-        Preconditions.checkNotNull(pnoSettings, "pnoSettings cannot be null");
+        Objects.requireNonNull(listener, "listener cannot be null");
+        Objects.requireNonNull(pnoSettings, "pnoSettings cannot be null");
         int key = addListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
@@ -1058,8 +1058,8 @@
     @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
     public void startDisconnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings,
             PnoScanListener listener) {
-        Preconditions.checkNotNull(listener, "listener cannot be null");
-        Preconditions.checkNotNull(pnoSettings, "pnoSettings cannot be null");
+        Objects.requireNonNull(listener, "listener cannot be null");
+        Objects.requireNonNull(pnoSettings, "pnoSettings cannot be null");
         int key = addListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
@@ -1074,7 +1074,7 @@
      */
     @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
     public void stopPnoScan(ScanListener listener) {
-        Preconditions.checkNotNull(listener, "listener cannot be null");
+        Objects.requireNonNull(listener, "listener cannot be null");
         int key = removeListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();